This question already has answers here:
How can I sort arrays and data in PHP?
(14 answers)
Closed last year.
This is the result of dd() that I use in my controller on laravel 8. I want to sort the data based on the JB column. I can't use the manual order by in SQL syntax because I get JB from complex DB RAW. Therefore I want to sort this multi-dimensional array using php. Does anyone know how to sort the multi-dimensional array based on JB column value?
here I go...
you can use array_multisort PHP function. Link
$new = [
[
'id' => 13,
'name' => 'Tony',
'jb' => 3,
],
[
'id' => 15,
'name' => 'Joe',
'jb' => 2,
],
[
'id' => 16,
'name' => 'Ross',
'jb' => 1,
],
[
'id' => 18,
'name' => 'Monika',
'jb' => 5,
],
[
'id' => 20,
'name' => 'Joye',
'jb' => 7,
],
];
$keys = array_column($new, 'jb');
array_multisort($keys, SORT_ASC, $new);
so as a result you will get link,
Array
(
[0] => Array
(
[id] => 16
[name] => Ross
[jb] => 1
)
[1] => Array
(
[id] => 15
[name] => Joe
[jb] => 2
)
[2] => Array
(
[id] => 13
[name] => Tony
[jb] => 3
)
[3] => Array
(
[id] => 18
[name] => Monika
[jb] => 5
)
[4] => Array
(
[id] => 20
[name] => Joye
[jb] => 7
)
)
sortBy method solves your issue. Laravel really has a strong bunch of methods in collections. Below code block shows an example.
$collection = collect([
['name' => 'Desk', 'price' => 200],
['name' => 'Chair', 'price' => 100],
['name' => 'Bookcase', 'price' => 150],
]);
$sorted = $collection->sortBy('price');
$sorted->values()->all();
/*
[
['name' => 'Chair', 'price' => 100],
['name' => 'Bookcase', 'price' => 150],
['name' => 'Desk', 'price' => 200],
]
*/
Related
This question already has answers here:
Sort multidimensional array based on another array [duplicate]
(3 answers)
Closed 26 days ago.
Hi I have an array that looks like this
array[
0 => array[
'id' => 1,
'name' => 'Test 1'
'classId' => 3
],
1 => array[
'id' => 1,
'name' => 'Test 1'
'classId' => 15
],
2 => array[
'id' => 1,
'name' => 'Test 1'
'classId' => 17
],
]
And I have another array that contains classIds like:
classIds = [15, 17, 3]
And I want to sort my array based on classIds
I can do a a double loop to compare it. I am just wondering is there anyother way to get it done?
Actually one loop i enough:
<?php
$order = [15, 17, 3];
$input = [
[
'id' => 1,
'name' => 'Test 1',
'classId' => 3,
],
[
'id' => 1,
'name' => 'Test 1',
'classId' => 15,
],
[
'id' => 1,
'name' => 'Test 1',
'classId' => 17,
],
];
$output = [];
array_walk($input, function($entry) use ($order, &$output) {
$output[array_search($entry['classId'], $order)] = $entry;
});
ksort($output);
print_r($output);
In case you consider array_search(...) also a "loop" (though it internally works different), that would be an alternative which produces the same output:
<?php
$order = array_flip([15, 17, 3]);
$input = array_values([
[
'id' => 1,
'name' => 'Test 1',
'classId' => 3,
],
[
'id' => 1,
'name' => 'Test 1',
'classId' => 15,
],
[
'id' => 1,
'name' => 'Test 1',
'classId' => 17,
],
]);
$output = [];
array_walk($input, function($entry, $index) use ($order, &$output) {
$output[$order[$entry['classId']]] = $entry;
});
ksort($output);
print_r($output);
The output of both approaches is:
Array
(
[0] => Array
(
[id] => 1
[name] => Test 1
[classId] => 15
)
[1] => Array
(
[id] => 1
[name] => Test 1
[classId] => 17
)
[2] => Array
(
[id] => 1
[name] => Test 1
[classId] => 3
)
)
You can sort the array directly and in-place using usort and an anonymous comparison function that retrieves the target indices from $classIds.
Given
<?php
$arr = array(
0 => array(
'id' => 1,
'name' => 'Test 1',
'classId' => 3
),
1 => array(
'id' => 1,
'name' => 'Test 1',
'classId' => 15
),
2 => array(
'id' => 1,
'name' => 'Test 1',
'classId' => 17
),
);
$classIds = [15, 17, 3];
you can sort $arr with
// Create assoc array mapping classIds to their desired sorted position.
$classIdsOrder = array_combine($classIds, range(0, count($classIds)-1));
// Sort $arr according to the 'classId' order described by $classIdsOrder
usort($arr, function ($left, $right) use ($classIdsOrder) {
return $classIdsOrder[$left['classId']] <=> $classIdsOrder[$right['classId']];
});
print_r($arr);
which outputs
Array
(
[0] => Array
(
[id] => 1
[name] => Test 1
[classId] => 15
)
[1] => Array
(
[id] => 1
[name] => Test 1
[classId] => 17
)
[2] => Array
(
[id] => 1
[name] => Test 1
[classId] => 3
)
)
Try it online!
I am using php 7.1.
I have seen that to eliminate the duplicate elements it is enough with this
array_unique($array, SORT_REGULAR);
I've also seen this work
array_map("unserialize", array_unique(array_map("serialize", $array)));
But that only deletes the elements that are duplicated from the array, I want to delete those that are duplicated but I don't want it to leave me only 1 without a duplicate, I want it to also delete that original on which it has been based to verify that it is duplicated
How could I do it?
For example i have this
$array = array(
[0] = array(
[id] => 1,
[number] => 12345,
[date] => 2022-05-09
)
[1] = array(
[id] => 2,
[number] => 123456,
[date] => 2022-05-09
)
[2] = array(
[id] => 3,
[number] => 123456,
[date] => 2022-05-09
)
[3] = array(
[id] => 3,
[number] => 123456,
[date] => 2022-05-09
)
)
How can i let it become this:?
$array = array(
[0] = array(
[id] => 1,
[number] => 12345,
[date] => 2022-05-09
)
[1] = array(
[id] => 2,
[number] => 123456,
[date] => 2022-05-09
)
)
This should be straightforward. Pluck all IDs using array_column and use array_count_values to get counts of occurrences of each ID. Then, use array_filter to filter only unique ones.
<?php
$unique_ids = array_count_values(array_column($array,'id'));
$res = array_filter($array, fn($v) => $unique_ids[$v['id']] === 1);
print_r($res);
Online Demo
Implementing the advice from How to remove values from an array if occurring more than one time?, for best time complexity, keep a lookup array of previously encountered values and their index. When a value is encountered more than once, delete the current and original row from the input array. It is perfectly safe to call unset() on an element that has already been unset(), no breakage will occur.
I have extended your input array to demonstrate that unset() will not cause trouble. I am using "array destructuring" in the foreach() to make the code more concise.
Code: (Demo)
$array = [
['id' => 1, 'number' => 12345, 'date' => '2022-05-09'],
['id' => 2, 'number' => 123456, 'date' => '2022-05-09'],
['id' => 3, 'number' => 123456, 'date' => '2022-05-09'],
['id' => 3, 'number' => 123456, 'date' => '2022-05-09'],
['id' => 4, 'number' => 123457, 'date' => '2022-05-10'],
['id' => 4, 'number' => 123458, 'date' => '2022-05-11'],
['id' => 3, 'number' => 123459, 'date' => '2022-05-12']
];
$found = [];
foreach ($array as $index => ['id' => $id]) {
if (isset($found[$id])) {
unset($array[$index], $array[$found[$id]]);
} else {
$found[$id] = $index;
}
}
var_export($array);
Output:
array (
0 =>
array (
'id' => 1,
'number' => 12345,
'date' => '2022-05-09',
),
1 =>
array (
'id' => 2,
'number' => 123456,
'date' => '2022-05-09',
),
)
I searched a lot of SOF threads and no one seems to stick to my problem. What's kind of wired because this should be a well discussed question :)
Maybe I'm seeking for the wrong thing...
Scenario:
I have 2 arrays
$a = [
['id' => 5, 'name' => 'bruce'],
['id' => 7, 'name' => 'wayne']
];
// 2 elements
and
$b = [
['id' => 6, 'name' => 'chuck'],
['id' => 8, 'name' => 'norris'],
['id' => 7, 'name' => 'wayne'] //also exists in array $a
];
// 3 elements
My goal is
$c = [
['id' => 6, 'name' => 'chuck'],
['id' => 8, 'name' => 'norris'],
['id' => 7, 'name' => 'wayne'],
['id' => 5, 'name' => 'bruce']
];
// 4 elements (no duplicates)
I really don't care about the order inside the array(s) but I want to merge both into one, without having duplicates.
I tried array_merge and array_merge_recursive. No one works. Probably because the functions doesn't know the identifier which identifies each entry. Is there an easy solution or do I really have to create an own method/function for this?
Maybe there is a closure that I could use?
You can do this with very simple inbuilt function of PHP
$c = array_unique(array_merge($a,$b), SORT_REGULAR);
print_r( $c )
The output of the print_r is
Array
(
[0] => Array
(
[id] => 5
[name] => bruce
)
[1] => Array
(
[id] => 7
[name] => wayne
)
[2] => Array
(
[id] => 6
[name] => chuck
)
[3] => Array
(
[id] => 8
[name] => norris
)
)
$temp = array_merge($b, $a);
foreach ($temp as $v) {
$c[$v['id']] = $v;
}
If it finds the same id, the element will be overwritten in $c
Here's an approach at hashing each array with serialize after a key sort:
<?php
$a = [
['id' => 5, 'name' => 'bruce'],
['id' => 7, 'name' => 'wayne']
];
$b = [
['id' => 6, 'name' => 'chuck'],
['name' => 'wayne', 'id' => 7],
['id' => 8, 'name' => 'norris']
];
$merged = array_merge($a, $b);
foreach($merged as $k => $v) {
ksort($v);
$hashes[$k] = serialize($v);
}
$hashes = array_unique($hashes);
var_export(array_intersect_key($merged, $hashes));
Output:
array (
0 =>
array (
'id' => 5,
'name' => 'bruce',
),
1 =>
array (
'id' => 7,
'name' => 'wayne',
),
2 =>
array (
'id' => 6,
'name' => 'chuck',
),
4 =>
array (
'id' => 8,
'name' => 'norris',
),
)
If you index them on unique id then just add them. The result will be indexed on id which is convenient:
$result = array_column($a, null, 'id') + array_column($b, null, 'id');
I don't know how performant this is, but just using phps array-manipulation functions I get:
>>> array_values(array_merge(array_combine(array_column($a, 'name'), $a), array_combine(array_column($b, 'name'), $b)));
=> [
[
"id" => 5,
"name" => "bruce",
],
[
"id" => 7,
"name" => "wayne",
],
[
"id" => 6,
"name" => "chuck",
],
[
"id" => 8,
"name" => "norris",
],
]
This question already has answers here:
Is there a function to extract a 'column' from an array in PHP?
(15 answers)
Closed 6 years ago.
I am trying to get values for each field eg. translation in subarrays without foreach. Is it possible?
Array
(
[0] => Array
(
[group_id] => 11
[group_translation] => Extras
[id] => 21
[operation] => +
[price] => 5
[price_by] => once
[price_type] => fixed
[translation] => Pick up
[price_total] => 5
)
[1] => Array
(
[group_id] => 11
[group_translation] => Extras
[id] => 22
[operation] => +
[price] => 10
[price_by] => once
[price_type] => fixed
[translation] => Drinks
[price_total] => 10
)
)
Thank you!
Sure that is possible:
<?php
$data = [
[
'group_id' => 11,
'group_translation' => 'Extras',
'id' => 21,
'operation' => '+',
'price' => 5,
'price_by' => 'once',
'price_type' => 'fixed',
'translation' => 'Pick up',
'price_total]' => 5
],
[
'group_id' => 11,
'group_translation' => 'Extras',
'id' => 22,
'operation' => '+',
'price' => 10,
'price_by' => 'once',
'price_type' => 'fixed',
'translation' => 'Drinks',
'price_total' => 10
]
];
$extract = [];
array_walk($data, function($element) use (&$extract) {
$extract[] = $element['translation'];
});
var_dump($extract);
The output obviously is:
array(2) {
[0] =>
string(7) "Pick up"
[1] =>
string(6) "Drinks"
}
I have a multidimensional indexed array. Each element is an associative array with an id column which is unique between elements (its value never repeats within the array).
[indexed] =>Array
(
[0] => Array
(
[id] => john
[name] => John
[age] => 29
),
[1] => Array
(
[id] => peter
[name] => Peter
[age] => 30
),
[2] => Array
(
[id] => harry
[name] => Harry
[age] => 19
)
)
My goal is to convert this array into a multidimensional associative array, indexed by id values.
[indexed] =>Array
(
[john] => Array
(
[id] => john
[name] => John
[age] => 29
),
[peter] => Array
(
[id] => peter
[name] => Peter
[age] => 30
),
[harry] => Array
(
[id] => harry
[name] => Harry
[age] => 19
)
)
My best attempt so far is to loop over array elements and manually create the final array.
$associative = array();
foreach($indexed as $key=>$val) $associative[$val['id']] = $val;
I think it's not the most elegant solution. Is it possible to obtain the same result with built-in (more efficient) functions?
The truth is php DOES offer a single, native function that allows you to replace the outer indexes with the values of a single column. The "magic" is in the 2nd parameter which tells php not to touch the subarray values when assigning the new keys.
Code: (Demo)
$indexed = [
['id' => 'john', 'name' => 'John', 'age' => 29],
['id' => 'peter', 'name' => 'Peter', 'age' => 30],
['id' => 'harry', 'name' => 'Harry', 'age' => 19],
];
var_export(array_column($indexed, null, 'id'));
Output:
array (
'john' =>
array (
'id' => 'john',
'name' => 'John',
'age' => 29,
),
'peter' =>
array (
'id' => 'peter',
'name' => 'Peter',
'age' => 30,
),
'harry' =>
array (
'id' => 'harry',
'name' => 'Harry',
'age' => 19,
),
)
This even works on an array of objects. The end result is an array of objects with new, associative first-level keys. (Demo)
$indexed = [
(object)['id' => 'john', 'name' => 'John', 'age' => 29],
(object)['id' => 'peter', 'name' => 'Peter', 'age' => 30],
(object)['id' => 'harry', 'name' => 'Harry', 'age' => 19],
];
var_export(array_column($indexed, null, 'id'));
Output:
array (
'john' =>
(object) array(
'id' => 'john',
'name' => 'John',
'age' => 29,
),
'peter' =>
(object) array(
'id' => 'peter',
'name' => 'Peter',
'age' => 30,
),
'harry' =>
(object) array(
'id' => 'harry',
'name' => 'Harry',
'age' => 19,
),
)
Here is another way of doing it (assuming $arr is your original array):
$associative = array_combine(array_map(function($item) { return $item['id']; }, $arr), $arr);
But I think using a foreach is still shorter and more readable compare to this.