Get max value from each column of a 2-dimensional array - php

I have an array within an array, for example:
[
[0, 20, 5],
[5, 0, 15],
[5, 10, 0]
]
I need to get the max number in each column.
The max of [0 , 5 , 5] is 5, so that goes into the result array.
The max of [20, 0, 10] is 20, so that goes into the result array.
The max of [5, 15, 0] is 15, so that goes into the result array.
The final result array must contain [5, 20, 15].

First, the array has to be transposed (flip the rows and columns):
function array_transpose($arr) {
$map_args = array_merge(array(NULL), $arr);
return call_user_func_array('array_map', $map_args);
}
(taken from Is there better way to transpose a PHP 2D array? - read that question for an explanation of how it works)
Then, you can map the max function on the new array:
$maxes = array_map('max', array_transpose($arr));
Example: http://codepad.org/3gPExrhO
Output [I think this is what you meant instead of (5, 15, 20) because you said index 1 should be max of (20, 0, 10)]:
Array
(
[0] => 5
[1] => 20
[2] => 15
)

Without the splat operator, array_map() with max() will return the max value for each row. ([20, 15, 10])
With the splat operator to transpose the data structure, the max value for each column is returned.
Code: (Demo)
$array = [
[0, 20, 5],
[5, 0, 15],
[5, 10, 0]
];
var_export(
array_map('max', ...$array)
);
Output:
array (
0 => 5,
1 => 20,
2 => 15,
)

Related

how to get same values if an array have values same with values of anther array values in PHP?

Having two arrays of authRoom and partiRoom with one same value inside them. Want to find that same value if it was matched
Found array_search function that work only with single variable
$authRoom = [8, 7, 1, 22, 13, 18, 10];
$partiRoom= [3, 6, 5, 9, 8];
I want the output to be 8 which is the same value of these two arrays
You can use array_intersect which will give you an array of the same values in both $authRoom and $partiRoom like so:
$authRoom = [8, 7, 1, 22, 13, 18, 10];
$partiRoom = [3, 6, 5, 9, 8];
$res = array_intersect($authRoom, $partiRoom);
print_r($res); // [8]
If you want to get the value 8 outside of the array, you can simply access the first value using index 0:
$res = array_intersect($authRoom, $partiRoom)[0];
echo $res; // 8

Compare the new array with the previous one

I have an array with 4 elements
[1, 2, 3, 4]
So far I am printing several arrays, all with different elements in each array, to a limit set by me.
for($i = 0; $i<=100; $i++){//...
Output so far:
[11, 22, 32, 44]
[22, 33, 44, 45]
[12, 24, 25, 31]
[15, 16, 31, 41]
[22, 33, 44, 45]//already exist
[11, 22, 32, 44]//already exist
...
How can I compare an outgoing array to the next one going out and delete the new one if is equal to the previous array?
You could create a key for an array with the help of implode() and have a set array which has this key. If key is already present, then the current array in iteration is a duplicate one, else it's a new one. Remember to sort the current array as the order of the numbers matter here for proper key check.
<?php
$arr = [
[11, 22, 32, 44],
[22, 33, 44, 45],
[12, 24, 25, 31],
[15, 16, 31, 41],
[22, 33, 44, 45],
[44, 22, 32, 11]
];
$set = [];
foreach($arr as $curr_array){
sort($curr_array);
$hash = implode("|",$curr_array);
if(isset($set[$hash])) echo "Duplicate",PHP_EOL;
else{
print_r($curr_array);
$set[$hash] = true;
}
}
Demo: https://3v4l.org/EXXRu

Laravel 5.8 update mysql json column cast as array changes data stored format

I have a table with a json column cast as array. The Schema creation has the column defined like this:
$table->json('row_ids');
In my class:
protected $casts = [
'row_ids' => 'array',
];
I generate the data in this array / column by getting every row id from another table like this:
$id_array = DB::table($table->name)->pluck('api_id')->toArray();
TableChannelRow::create([
'table_api_id' => $table->api_id,
'channel_api_id' => $channel->api_id,
'row_ids' => $id_array,
]);
When I dd a collection record I can see the columns in the target table OK, with one of the columns containing an array as expected:
#attributes: array:4 [▼
"api_id" => 2
"table_api_id" => 1
"channel_api_id" => 6
"row_ids" => "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, ▶"
]
When I check in MySQLWorkbench the data looks like this:
In another controller I want to add or remove entries from the array in this column like this:
$table_channel_row = TableChannelRow::where('table_api_id', '=', $rowId)
->where('channel_api_id', '=', $channelId)
->first();
$row_ids = $table_channel_row->row_ids;
if ($is_checked == 'yes') {
// Add value to array if it does not already exist
if (!in_array($row_id, $row_ids)) {
array_push($row_ids, $row_id);
}
} else {
// Remove value from array
$row_id_array[] = $row_id;
$row_ids = array_diff($row_ids, $row_id_array);
}
$table_channel_row->update([
'row_ids' => $row_ids,
]);
Now the data in MySQLWorkbench looks like this:
Why does it get stored looking like a PHP array in the first instance, then later on update it gets stored as a json object?
Additionally the remove PHP code is working, yet the add is not, though it does not trigger an exception (you can see the first value is removed in the second image, but I cannot find it in the object in MySQL when I trigger the code to add it)
What did I miss? Thanks!
The reason why it's saving differently is because array_diff returns an associative array whereas your initial data is an indexed array. Take the following for example:
$ids = [1, 2, 3, 4, 5];
$ids2 = [1, 2, 3];
Then if you perform an array_diff($ids, $ids2), it would return the following:
[
3 => 4,
4 => 5
]
So if you want to save as the same format as your initial one, you have to retrieve the values of the array using array_values:
$row_ids = array_values(array_diff($row_ids, $row_id_array));

Select multiple random column values from a two-dimensional array

I want to select 5 random ID's from my array of rows. Here is my array $test:
$test = [
['id' => 13, 'pets' => 8],
['id' => 15, 'pets' => 8],
['id' => 16, 'pets' => 10],
['id' => 17, 'pets' => 9],
['id' => 18, 'pets' => 10],
['id' => 19, 'pets' => 10],
['id' => 20, 'pets' => 0],
['id' => 21, 'pets' => 8],
['id' => 22, 'pets' => 9],
['id' => 23, 'pets' => 4],
['id' => 24, 'pets' => 0],
['id' => 40, 'pets' => 8],
['id' => 43, 'pets' => 2],
];
How can I select 5 random ID's from the array and put them into a string like this:
$ids = '13,17,18,21,43';
I've tried to use array_rand(), but it does not seem to work for my type of array. I'm not sure if there are any other built in PHP functions that can do this type of job or if I have to create my own function. It would be nice to have my own function like this to plug in the number of required values.
You can use array_column to only get the ID's and shuffle them.
Then use array_slice to get five items and implode.
$id = array_column($arr, "id");
Shuffle($id);
Echo implode(",", array_slice($id, 0, 5));
First extract the id column indexing also by the id, then pick 5 random ones, and finally implode into a comma separated list. Since keys must be unique, this has the added benefit of not returning duplicate ids if there happen to be duplicates in the array:
$ids = implode(',', array_rand(array_column($test, 'id', 'id'), 5));
For a function:
function array_rand_multi($array, $key, $num) {
return implode(',', array_rand(array_column($array, $key, $key), $num));
}
If you want random, unique ids in a random order, I recommend shuffling the array, then isolating upto 5 subarrays, then extracting the id values, then joining with commas. This way array_column() doesn't need to iterate the full array.
Code: (Demo)
shuffle($test);
echo implode(
',',
array_column(
array_slice($test, -5),
'id'
)
);
If you want random, unique ids and don't mind that they will be in the same order as your input rows, then array_rand() can be used.
#AbraCadaver's approach works by applying temporary keys to the input array, picking five random keys, then joining with commas. Because the values inside the rows are never used, null can also be used as array_column()'s second parameter. These approaches should not be used if duplicate ids need to be honored. In other words, because id values are being applied to the first level keys, php will automatically destroy any rows with duplicated ids -- because a single level of an array cannot contain duplicate keys.
One way to avoid potentially destroying data is to call array_rand() on the original indexes of the input array, then filter those unique indexes by 5 randomly selected indexes. (Demo)
echo implode(
',',
array_column(
array_intersect_key(
$test,
array_flip(array_rand($test, 5))
),
'id'
)
);
Finally, if you want 5 randomly selected, randomly ordered ids which may be selected more than once, then just make 5 iterated calls of array_rand(). (Demo)
for ($x = 0, $delim = ''; $x < 5; ++$x, $delim = ',') {
echo $delim . $test[array_rand($test)]['id'];
}
Or (Demo)
echo implode(
',',
array_map(
fn() => $test[array_rand($test)]['id'],
range(1, 5)
)
);
You can proceed like this (short example) :
<?php
$items = array(
array("id" => 43, "pets" =>2),
array("id" => 40, "pets" =>8),
array("id" => 24, "pets" =>0),
array("id" => 23, "pets" =>4),
);
$ids = $items[array_rand($items)]["id"].",".$items[array_rand($items)]["id"].",".$items[array_rand($items)]["id"];
echo $ids;
// Output Example : 24, 40, 23
?>
It will choose a random key from the main array ($items), example : 3, and output the "id" :
$items[3]["id"]
for this example.
Here is a demo : http://sandbox.onlinephpfunctions.com/code/32787091e341cdf8e172d96b065b14b3ca834846

How to get array key with less than values

I have 2 arrays:
$arr_1=array(200, 300, 200, 200);
$arr_2=array(
1 => array(70, 90, 70, 20),
2 => array(115, 150, 115, 35),
3 => array(205, 250, 195, 55),
4 => array(325, 420, 325, 95),
5 => array(545, 700, 545, 155)
);
Now I need some way to get array keys for arrays in $arr_1 where all their values are less than all values from $arr_2.
In the above example it must return key 1 AND key 2 from $arr_2 without using a foreach loop.
You can use array_filter to filter the elements (it preserves keys) and then pass the result to array_keys to receive an array of keys.
Also, your condition can be spelled this way: "return subarrays from $arr_2 where highest value is smaller than smallest value of $arr_1."
$arr_1=array(200, 300, 200, 200);
$arr_2=array(
1 => array(70, 90, 70, 20),
2 => array(115, 150, 115, 35),
3 => array(205, 250, 195, 55),
4 => array(325, 420, 325, 95),
5 => array(545, 700, 545, 155)
);
$filtered = array_filter($arr_2, function($value) use ($arr_1) {
return max($value) < min($arr_1);
});
$keys = array_keys($filtered);
var_dump($keys);
If you are only interested in comparing the subarrays against the lowest value in $arr_1, then best practices dictates that you declare that value before entering the array_filter(). This will spare the function having to call min() on each iteration. (Demo)
$arr_1=[200,300,200,200];
$arr_2=[
1=>[70,90,70,20],
2=>[115,150,115,35],
3=>[205,250,195,55],
4=>[325,420,325,95],
5=>[545,700,545,155]
];
$limit=min($arr_1); // cache this value, so that min() isn't called on each iteration in array_filter()
$qualifying_keys=array_keys(array_filter($arr_2,function($a)use($limit){return max($a)<$limit;}));
var_export($qualifying_keys);
/*
array(
0=>1,
1=>2,
)
*/

Categories