Shuffle array by group of values - php

I'm looking for a way to shuffle an array by groups of values in PHP.
For example, I have a sorted array :
Array
(
[peter] => 100
[paul] => 100
[mary] => 50
[andrew] => 50
[bill] => 50
[jason] => 10
[sofia] => 10
)
And I'd like to shuffle it this way :
Array
(
[paul] => 100
[peter] => 100
[mary] => 50
[bill] => 50
[andrew] => 50
[jason] => 10
[sofia] => 10
)
Would you know a smart way to do this, or will I have to write a dirty foreach-based script ?

With this user defined function shuffle_assoc you can shuffle your array before sorting.
function shuffle_assoc(&$array) {
$keys = array_keys($array);
shuffle($keys);
foreach($keys as $key) {
$new[$key] = $array[$key];
}
$array = $new;
return true;
}
$array = array('peter' => 100
, 'paul' => 100
, 'mary' => 50
, 'andrew' => 50
, 'bill' => 50
, 'jason' => 10
, 'sofia' => 10);
shuffle_assoc($array);
asort($array);
array_reverse($array);
var_dump($array);

I found the answer by using both arsort and the function shuffle_assoc() that is discribed in the first user contribution on this page : PHP: shuffle
function shuffle_assoc(&$array) {
$keys = array_keys($array);
shuffle($keys);
foreach($keys as $key) {
$new[$key] = $array[$key];
}
$array = $new;
return true;
}
$array = array(
'peter' => 100,
'paul' => 100,
'mary' => 50,
'andrew'=> 50,
'bill' => 50,
'jason' => 10,
'sofia' => 10
);
shuffle_assoc($array);
arsort($array);
print_r($array);

Related

fill in the multidimensional array with missing keys

I have the following multidimensional array. I had to create keys the way it looks to group them accordingly.
Array
(
[Oranges] => Array
(
[Name] => Oranges
[l.VA123] => 17
[l.MA123] => 12
[l.GA123] => 9
[l.CT123] => 5
)
[Apple] => Array
(
[Name] => Apple
[l.CA123] => 13
)
[Grapes] => Array
(
[Name] => Grapes
[l.WI123] => 8
[l.FL123] => 5
)
)
However, I need all the subarrays to have the same keys. Missing ones should be filled with a value of 0. The final array should be like below so that all subarrays have equal length.
Array
(
[Oranges] => Array
(
[Name] => Oranges
[l.VA123] => 17
[l.MA123] => 12
[l.GA123] => 9
[l.CT123] => 5
[l.CA123] => 0
[l.WI123] => 0
[l.FL123] => 0
)
[Apple] => Array
(
[Name] => Apple
[l.CA123] => 13
[l.WI123] => 0
[l.FL123] => 0
[l.VA123] => 0
[l.MA123] => 0
[l.GA123] => 0
[l.CT123] => 0
)
[Grapes] => Array
(
[Name] => Grapes
[l.WI123] => 8
[l.FL123] => 5
[l.CA123] => 0
[l.VA123] => 0
[l.MA123] => 0
[l.GA123] => 0
[l.CT123] => 0
)
)
You need a simple + operator. As from manual:
The + operator returns the right-hand array appended to the left-hand array; for keys that exist in both arrays, the elements from the left-hand array will be used, and the matching elements from the right-hand array will be ignored.
$items = Array
(
'Oranges' => Array
(
'Name' => 'Oranges',
'l.VA123' => 17,
'l.MA123' => 12,
'l.GA123' => 9,
'l.CT123' => 5,
),
'Apple' => Array
(
'Name' => 'Apple',
'l.CA123' => 13,
),
'Grapes' => Array
(
'Name' => 'Grapes',
'l.WI123' => 8,
'l.FL123' => 5,
),
);
// static keys
$keys = [
'l.VA123' => 0,
'l.MA123' => 0,
'l.GA123' => 0,
'l.CT123' => 0,
'l.CA123' => 0,
'l.WI123' => 0,
'l.FL123' => 0,
];
// keys generated from source array, tricky approach
$keys = array_fill_keys(
// here we merge all elements of `$items` into one array
// as keys are repeated - you definitely got all keys that
// can be in `$items`, `array_keys` will give you these keys
// `array_fill_keys` will create array where key is what you need
// and value is 0.
array_keys(call_user_func_array('array_merge', $items)),
0
);
// keys generated from source array, SIMPLE approach
$keys = [];
foreach ($items as $item) {
foreach ($item as $k => $v) {
if ($k != 'Name') {
$keys[$k] = 0;
}
}
}
foreach ($items as &$item) {
$item = $item + $keys;
}
print_r($items);
Probably someone can come up with something more efficient, but without a list of keys that you want, I think you'll need to take a couple of passes of the array:
<?php
$fruits = [
"Oranges"=>["Name"=>"Oranges", "l.VA123"=>17, "l.MA123"=>12, "1.GA123"=>9, "1.CT123"=>5],
"Apple"=>["Name"=>"Apple", "1.CA123"=>13],
"Grapes"=>["Name"=>"Grapes", "1.WI123"=>8, "1.FL123"=>5]
];
$keys = [];
foreach ($fruits as $fruit) {
unset($fruit["Name"]);
$keys = array_merge($keys, array_keys($fruit));
}
$keys = array_fill_keys(array_unique($keys), 0);
foreach ($fruits as &$fruit) {
$fruit = array_merge($keys, $fruit);
}
print_r($fruits);
Since all keys and default values are "known", create an associative array, use a foreach() and modify the rows by reference, and use the union-assignment (combined) operator. This will allow the original values to overwrite the default values.
Code: (Demo)
$keys = [
'l.VA123' => 0,
'l.MA123' => 0,
'l.GA123' => 0,
'l.CT123' => 0,
'l.CA123' => 0,
'l.WI123' => 0,
'l.FL123' => 0,
];
foreach ($items as &$row) {
$row += $keys;
}
var_export($items);
If you want the keys to be consistently positioned, then use array_replace() or array_merge() instead of the union assignment operator.
Code: (Demo)
foreach ($items as &$row) {
$row = array_replace($keys, $row);
}

get max and min value each column in multdimensional array php

I have a multidimensional array
$array1 = array(
0 => array(34554, 45, 4545454),
1 => array(434534, 35, 345345),
2 => array(43534, 35, 4343445),
3 => array(35534, 34, 342323)
);
Can we find the minimum and maximum value for each value? if we want to find min for first and second column, the other column is max, and the result array is
$array2 = array(
0=>34554,
1=>34,
2=>4545454
);
i've tried this to get min
$result = array(); // save result
array_walk_recursive($ary, function($v, $k) use (&$result) {
if (!isset($result[$k])) $result[$k] = $v;
elseif ($result[$k] > $v) $result[$k] = $v;
});
print_r ($result);
and tried this to get max
$result = array(); // save result
array_walk_recursive($ary, function($v, $k) use (&$result) {
if (!isset($result[$k])) $result[$k] = $v;
elseif ($result[$k] < $v) $result[$k] = $v;
});
print_r ($result);
Thank you.
try below solution:
$array1 = array(
0 => array(34554, 45, 4545454),
1 => array(434534, 35, 345345),
2 => array(43534, 35, 4343445),
3 => array(35534, 34, 342323)
);
//max values
$max_arr = array_map(function ($val) {
return max($val);
}, $array1);
print_r($max_arr);
//min values
$min_arr = array_map(function ($val) {
return min($val);
}, $array1);
print_r($min_arr);
//min and max values
$min_max_arr = array_map(function ($val) {
return array('min' => min($val), 'max' => max($val));
}, $array1);
print_r($min_max_arr);
output:
//max values
Array
(
[0] => 4545454
[1] => 434534
[2] => 4343445
[3] => 342323
)
//min values
Array
(
[0] => 45
[1] => 35
[2] => 35
[3] => 34
)
//min and max values
Array
(
[0] => Array
(
[min] => 45
[max] => 4545454
)
[1] => Array
(
[min] => 35
[max] => 434534
)
[2] => Array
(
[min] => 35
[max] => 4343445
)
[3] => Array
(
[min] => 34
[max] => 342323
)
)
I have added some more element so that you can notice how it works, I have arranged max min as key and value pair, if you will edit your question and show me what you want as output, I will update it.
<?php
$array1 = array(
0 => array(34554, 45, 4545454),
1 => array(434534, 35, 345345),
2 => array(43534, 35, 4343445),
3 => array(9355434, 34, 342323),
4 => array(35534, 34, 342323),
5 => array(8544534, 34, 342323),
6 => array(35534, 34, 342323)
);
foreach($array1 as $arr1){
$max = max($arr1);
$arr[$max] = min($arr1);
}
var_dump($arr);
output
array (size=6)
4545454 => int 45
434534 => int 35
4343445 => int 35
9355434 => int 34
342323 => int 34
8544534 => int 34

get set elements from array php

I have array in php :
Array
(
[id] => 1
[comp_id] => 1
[transaction_purpose] => 0
[source_of_funds] => 1
[beneficiary_relationship] => 0
[cus_occupation] => 0
[cus_id_image_2] => 0
[cus_id_image_3] => 0
[ben_id_type] => 0
[ben_id_number] => 1
)
I want to get only array key=>value pair if the valie is 1.
result array should be:
Array
(
[id] => 1
[comp_id] => 1
[source_of_funds] => 1
[ben_id_number] => 1
)
I tried with:
$returnArray = array();
foreach($mainArray as $r){
if($r>0){
array_push($returnArray, $mainArray);
}
}
But, It's giving me 4 times main array. Is there any way to achieve this? Thanks..
Just use array_filter():
$newarray = array_filter($array, function($var) {
return ($var === 1);
});
$newarray = array_filter($array);
Demo
$array = array(
'id' => 1,
'comp_id' => 1,
'transaction_purpose' => 0,
'source_of_funds' => 1,
'beneficiary_relationship' => 0,
'cus_occupation' => 0,
'cus_id_image_2' => 0,
'cus_id_image_3' => 0,
'ben_id_type' => 0,
'ben_id_number' => 1
);
$newarray = array_filter($array);
print_r($newarray);
Array
(
[id] => 1
[comp_id] => 1
[source_of_funds] => 1
[ben_id_number] => 1
)
Try this:
$returnArray = array_filter($result);
You can see PHP's array_filter function for more info.
Well, what else are you expecting to happen?
array_push($returnArray, $mainArray);
If you find an element which has >0 value, you push the ENTIRE original array onto the new one, not just the key/value you just tested.
You probably want:
$newarr = array();
foreach($mainArray as $key => $value) {
if ($value > 0) {
$newarr[$key] = $value;
}
}

PHP - array values out and get similar values

I have an array like this
Array ( [item1] => pack1 [amount1] => 1 [price1] => 25 [amount2] => 1 [price2] => 45 [item3] => pack3 [amount3] => 4 [price3] => 65 [sender] => Submit )
I need to get the values item1 & item3 out of the array, then remove the item on them with a
str_replace
Then find largest number with
max
just the first part that is the toughest, any ideas?
foreach through the array, if the key contains item then get/set the values. Also check the value to see if it's greater than the previous to get the max
$a = array( "item1" => "pack1", "amount1" => 1, "price1" => 25, "amount2" => 1, "price2" => 45, "item3" => "pack3");
$b = array();
$pattern = '/item[1-9]/';
$max_index = 0;
foreach($a as $key => $value){
if(preg_match($pattern, $key, $matches, PREG_OFFSET_CAPTURE)){
$index = str_replace("item","",$key);
$b[$index] = $value;
if($index > $max_index){
$max_index = $index;
}
}
}
$max_value = $b[$max_index];
echo $max_value;

merge arrays without reindexing keys

I have two arrays that I want to merge recursively, so adding arrays is not an option. This is simple example without multilevels to demonstrate the problem:
$a1 = Array(
5 => 'pronoun'
)
$a2 = Array(
2 => 'verb',
3 => 'noun'
)
$r = array_merge_recursive($a1, $a2)
And I want to get that resulting array:
Array(
5 => 'pronoun'
2 => 'verb',
3 => 'noun'
)
My problem is that array_merge_recursive function reindixes keys, and I get the following:
Array(
0 => 'pronoun'
1 => 'verb',
2 => 'noun'
)
I understand that's happening because all my keys are numeric. So I tried to make them string when adding but it doesn't seem to be working properly:
$a1[(string)7] = 'some value';
The key - 7 - is still number, or at least that's how it is displayed in debugger - $a1[7] and not $a1['7']. Any advice?
EDIT:
Addition of arrays is not an option. Please see why. I have two multilevel arrays:
$a1 = array (
1 => array (
1 => "man1",
2 => "man"
),
2 => array (
1 => "run",
2 => "nice"
)
);
$a2 = array(
2 => array (
1 => "to observe",
2 => "to examine visually"),
3 => array(
1 => "look nice",
2 => "appear, seem to be"));
$r = $a1 + $a2;
What I expect is the following:
$r = Array(
...
2 => array(
1 => array("run", "to observe")
2 => array("nice", "to examine visually")
));
But instead the options for the key 2 from the second array is not added:
$r = Array(
...
2 => array(
1 => "run",
2 => "nice"
));
you can just use $a1+$a2 to get your result
$a1 = array(
5 => 'pronoun'
);
$a2 = array(
2 => 'verb',
3 => 'noun'
);
print_r($a1+$a2);
For recursive array
$a1 = array(
5 => 'pronoun'
);
$a2 = array(array('a', 'z'), array(2 => 'p', 'q'));
print_r($a1+$a2);
Result is
Array
(
[5] => pronoun
[0] => Array
(
[0] => a
[1] => z
)
[1] => Array
(
[2] => p
[3] => q
)
)
is this what you want to achieve?
This should apply to your particular problem:
function assoc_merge(array $a, array $b)
{
$r = array();
foreach ($a as $key => $val) {
if (array_key_exists($key, $b) && is_array($val) == is_array($b[$key])) {
if (is_array($val)) {
$r[$key] = assoc_merge($a[$key], $b[$key]); // merge array
} else {
$r[$key] = array($val, $b[$key]); // merge entry
}
} else {
$r[$key] = $val; // just copy
}
}
return $r + $b; // add whatever we missed
}
print_r(assoc_merge($a1, $a2));
You can always try the manual case.
function merge () { // takes any number of arguments
$arrays = func_get_args();
$result = array();
foreach ($arrays as $array)
foreach ($array as $key => $item)
if (is_array($item))
$result = merge($result, $item);
else
$result[$key] = $item;
return $result;
Sure, it's slow, but it will work.
$a1 = array(
5 => 'pronoun'
);
$a2 = array(
2 => 'verb',
3 => 'noun'
);
foreach($a2 as $key=>$value) {
$a1[$key] = $value;
}
print_r($a1);
<?php
$a = [ 5 => 'pronoun'];
$b = [ 2 => 'verb', 3 => 'noun'];
$m = array_merge(array_keys($a), array_keys($b));
$final = array_combine($m, array_merge_recursive($a, $b));
print_r($final);

Categories