How to sort multidimensional arrays in PHP? - php

If I var_export I get
array (
0 =>
array (
'date' => 2017,
'id' => 128343,
),
1 =>
array (
'date' => 1976,
'id' => 128315,
),
2 =>
array (
'date' => 2006,
'id' => 128310,
),
3 =>
array (
'date' => 1967,
'id' => 128304,
),
4 =>
array (
'date' => 1938,
'id' => 128295,
),
5 =>
array (
'date' => 1978,
'id' => 128293,
),
6 =>
array (
'date' => 1997,
'id' => 128157,
),
7 =>
array (
'date' => 2000,
'id' => 128124,
),
The dates are mixed up. I am trying to sort those dates and keep the Ids attached to each date DESC in order then to loop again but ordered. I tried
function custom_sort_dt($a, $b) {
return $a['date'] - $b['date'];
}
usort($dateOrdered, "custom_sort_dt");
But I still get wrong order.
// the following gives a date
$myDate = (int)get_post_meta($id, 'usp-custom-14', true);
// this attaches the Id and the date
$dateOrdered[] = array("date"=>$myDate, "id"=>$id);

You could use array_multisort.
array_multisort($data, SORT_DESC, array_column($data, 'date'));
var_dump($data);
Note that this function operates on the original array. If you want a copy instead, build one before by
$copy = $data;

Perhaps try reversing the comparison to sort in descending order:
return $b['date'] - $a['date'];

Related

How can match two array in php

I have two array:
One Array
$workingDays = ['2019-11-01','2019-11-02','2019-11-03','2019-11-04'];
Other Array
$doneWork = array(
array(
'id' => 1,
'date' => '2019-11-01',
'work' => 'done'
),
array(
'id' => 1,
'date' => '2019-11-02',
'work' => 'done'
),
array(
'id' => 1,
'date' => '2019-11-04',
'work' => 'done'
)
);
My Question: How can check which date not exist in $doneWork array
You'd start by extracting the dates from $doneWork using array_map.
$doneWork = [
[
'id' => 1,
'date' => '2019-11-01',
'work' => 'done',
],
[
'id' => 1,
'date' => '2019-11-02',
'work' => 'done',
],
[
'id' => 1,
'date' => '2019-11-04',
'work' => 'done',
],
];
$doneWorkDays = array_map(function ($element) {
return $element['date'];
}, $doneWork);
print_r($doneWorkDays);
Will print:
Array ( [0] => 2019-11-01 [1] => 2019-11-02 [2] => 2019-11-04 )
Then check which elements in $workingDays are not in such array, using array_diff
$diff = array_diff($workingDays, $doneWorkDays);
print_r($diff);
Will print:
Array ( [2] => 2019-11-03 )
Pay attention, the result gives you not only the elements but also their index in the original array. If you don't care about these, use instead:
print_r(array_values($diff));
Why would anyone need such index? Well, perhaps you could need to report not only how many days were missed but also check if two missing elements are adjacent.
(the indexes are relevant only for the array you're comparing against. It doesn't matter in what position they appear in $doneWork )
Edit:
You say you need the results to be in "doneWork" format, which is an associative array with id (always zero), date and work (always 'absent').
Let's say your workin days are now
$workingDays = [
'2019-11-01',
'2019-11-02',
'2019-11-03',
'2019-11-04',
'2019-11-05'
];
So there are two missing days. Again, array map to the rescue:
// from previous answer
$diff = (array_diff($workingDays, $doneWorkDays));
// map each missing date to a doneWork array
$diff_assoc = array_values(
array_map(function($date) {
return [
'id' => 0,
'date' => $date,
'work' => 'absent'
];
},$diff)
);
That will return
Array
(
[0] => Array
(
[id] => 0
[date] => 2019-11-03
[work] => absent
)
[1] => Array
(
[id] => 0
[date] => 2019-11-05
[work] => absent
)
)
Again, note I'm wrapping the result in array_values because you need a plain array as result instead of:
Array
(
[2] => Array
(
[id] => 0
[date] => 2019-11-03
[work] => absent
)
[4] => Array
(
[id] => 0
[date] => 2019-11-05
[work] => absent
)
)
$nonExistingDates = [];
$doneWorkDays = [];
foreach($doneWork as $work) {
$doneWorkDays[] = $work['date'];
}
$nonExistingDates = array_diff($workingDays, $doneWorkDays);
// optional, removes duplicate dates
$nonExistingDates = array_unique($nonExistingDates);

How to copy items to existing array

I'm new in PHP. I have reviewed some other threads about the array combination but I couldn't found the answer.
For example the first array
array (
'date' => '01.06.2019',
'day' => 'Saturday',
)
Second array
array (
0 =>
array (
'id' => 10,
'name' => 'Mj phooi',
),
)
Expected result
array (
'date' => '01.06.2019',
'day' => 'Saturday',
'id' => 10,
'name' => 'Mj phooi',
)
I did try the array_combine and array_merge_recursive but it doesn't work. The closure result I tried is like $result = array_merge($arr,$temp);. It combined two arrays but there have two arrays inside which not match with the expected result.
You are almost there, you could use array_merge but the array in the $temp is a nested array so you might take the first index 0:
$arr = [
'date' => '01.06.2019',
'day' => 'Saturday',
];
$temp = [
[
'id' => 10,
'name' => 'Mj phooi',
]
];
print_r(array_merge($arr, $temp[0]));
Result:
Array
(
[date] => 01.06.2019
[day] => Saturday
[id] => 10
[name] => Mj phooi
)
See a php demo
Note that an array can not have duplicate keys so if they have the same keys the last will override the existing key.

Sort a multidimensional array by integer inside of a string value which is two levels down

I have a multidimensional array in php:
Array (
[0] => Array (
[certificate_name] => track.site
[domains] => track.site
[expiry_date] => Array (
[date] => 2018-09-25
[time] => 10:11:58
[count] => (22)
)
)
[1] => Array (
[certificate_name] => stats.com
[domains] => stats.com
[expiry_date] => Array (
[date] => 2018-09-24
[time] => 10:11:58
[count] => (43)
)
)
)
I want to sort this multidimensional array by $array['expiry_date']['count']
This can be done with usort:
$data = [
[
'certificate_name' => 'track.site',
'domains' => 'track.site',
'expiry_date' => [
'date' => '2018-09-25',
'time' => '10:11:58',
'count' => 22,
]
],
[
'certificate_name' => 'stats.com',
'domains' => 'stats.com',
'expiry_date' => [
'date' => '2018-09-24',
'time' => '10:11:58',
'count' => 43,
]
]
];
function compare_by_expiry_date_count($a, $b) {
return $a["expiry_date"]['count'] > $b["expiry_date"]['count'];
}
usort($data, "compare_by_expiry_date_count");
var_dump($data);
If I don't misunderstood your question then you need sorting by count not filtering. Also use trim() to remove parenthesis from the count value. Hope it helps :)
Try like this way, $b-$a is for desc, $a-$b is for asc
<?php
// this $b-$a is for desc, for asc try $a-$b
function sorting_by_count($a, $b)
{
return trim($b['expiry_date']['count'],'()') - trim($a['expiry_date']['count'],'()');
}
$array = [
[
'certificate_name' => 'track.site',
'domains' => 'track.site',
'expiry_date' => [
'date' => '2018-09-25',
'time' => '10:11:58',
'count' => '(22)',
]
],
[
'certificate_name' => 'stats.com',
'domains' => 'stats.com',
'expiry_date' => [
'date' => '2018-09-24',
'time' => '10:11:58',
'count' => '(43)',
]
]
];
usort($array, 'sorting_by_count');
print_r($array);
?>
DEMO: https://3v4l.org/vtRIu
For best time complexity, loop through your rows and populate a flat array containing the count values after trimming the parentheses and casting to an integer.
Then call array_multisort() with the counts array as the first argument and the original array as the second argument.
Code: (Demo)
foreach ($array as $row) {
$counts[] = (int) trim($row['expiry_date']['count'], '()');
}
array_multisort($counts, $array);
var_export($array);
Using usort() and calling trim() on every iteration will be more expensive because it will have to re-trim values that were already encountered.

If array value is repeated in another array, combine both arrays

I have several arrays that I want to check for a repeated value and if the value is found to be repeated in one of the other arrays, then combine both of those arrays together.
I give an example below of 2 arrays that have repeated values.
example: the value in purchase_order_number is the same in both arrays below. They are not unique values. But the values in tracking_number are unique.
I want to check if the value in purchase_order_number is repeated in another array. If the same value is found in another array, then combine both of those arrays into 1 array.
I'm trying to get the value in tracking_number and service combined into a single array when the value in purchase_order_number is the same in 2 or more arrays.
Example arrays below.
not combined
array (
'data' =>
array (
15 =>
array (
'type' => 'Tracking',
'id' => 2830143,
'attributes' =>
array (
'tracking_number' => '1Z5270560360309870',
'service' => 'UPS',
'order_id' => 2606218,
'purchase_order_number' => '7249491',
'recipient_attempts' => 1,
),
),
16 =>
array (
'type' => 'Tracking',
'id' => 2830144,
'attributes' =>
array (
'tracking_number' => '1Z5270560361740866',
'service' => 'UPS',
'order_id' => 2606218,
'purchase_order_number' => '7249491',
'recipient_attempts' => 1,
),
),
),
)
Example given below of how I need to combine the two above arrays.
Combined
array (
'data' =>
array (
16 =>
array (
'type' => 'Tracking',
'id' => 2830144,
'attributes' =>
array (
'tracking' =>
array (
0 =>
array (
'tracking_number' => '1Z5270560360309870',
'service' => 'UPS',
),
1 =>
array (
'tracking_number' => '1Z5270560361740866',
'service' => 'UPS',
),
),
'order_id' => 2606218,
'purchase_order_number' => '7249491',
'recipient_attempts' => 1,
),
),
),
)
Here's a reduce based solution with caveats:
$arr['data'] = array_reduce($arr['data'], function ($out, $item) {
// keys we want to extract
static $tracking_keys = ['tracking_number' => '', 'service' => ''];
// yank tracking keys from attributes
$tracking = array_intersect_key($item['attributes'], $tracking_keys);
$item['attributes'] = array_diff_key($item['attributes'], $tracking_keys);
// insert to new array based on order number
$order_no = $item['attributes']['purchase_order_number'];
if (!isset($out[$order_no])) {
$item['attributes']['tracking'] = [$tracking];
$out[$order_no] = $item;
} else {
array_push($out[$order_no]['attributes']['tracking'], $tracking);
}
return $out;
}, []);
Keys in 'data' are not retained and 'id' is set by the first item.

How to extract unique values from this multidimensional array?

How to extract unique values from this array.
I've tried another suggestion...
$input = array_map("unserialize", array_unique(array_map("serialize", $input)));
However because of the unix timestamp it wont work.
Im looking to extract only the second array index unique value and its array so should be left with..
// expected final
array(
2 => array(...),
3 => array(..)
)
$arr = array (
0 =>
array (
2 =>
array (
'date' => 1438173658,
'user' => 'admin',
),
),
1 =>
array (
2 =>
array (
'date' => 1438007944,
'user' => 'admin',
),
),
2 =>
array (
3 =>
array (
'date' => 1437746969,
'user' => 'supes',
),
)
)
Thanks.
Might be a simpler way, but here is one:
$result = array_intersect_key($arr,
array_unique(array_map(function($v) {
return current($v)['user'];
},
$arr)));

Categories