PHP - sort arrays within assoc array - php

I promise you I've had a look at the many existing SO Qs about PHP sorting, including this mega one
I've got a PHP associative array, with strings as keys. Each value is an array of integers. I want to sort each array of integers, in simple ascending numerical order. I'm convinced this should be easy, and I've found enough examples that I think I should be doing the right thing, but it's not quite working, so there's a typo or I'm an idiot or something...
PHP:
//Each fruit corresponds to an array (series) of integers
$data = [
'banana' => [
1,3,2
],
'orange' => [
5,1,3
]
];
echo "Before sort:\n";
var_dump($data);
//For each fruit, I want to order the numbers
foreach ($data as $key => $series)
{
//Sort array of integers
sort($series);
//NB I wasn't sure about value/reference details of foreach loops, so I also tried
//retrieving a series into a variable, sorting, and then reassigning back to the same key
}
echo "\n\nAfter sort:\n";
var_dump($data);
Output:
Before sort:
array(2) {
'banana' =>
array(3) {
[0] =>
int(1)
[1] =>
int(3)
[2] =>
int(2)
}
'orange' =>
array(3) {
[0] =>
int(5)
[1] =>
int(1)
[2] =>
int(3)
}
}
After sort:
array(2) {
'banana' =>
array(3) {
[0] =>
int(1)
[1] =>
int(3)
[2] =>
int(2)
}
'orange' =>
array(3) {
[0] =>
int(5)
[1] =>
int(1)
[2] =>
int(3)
}
}
As you can see, in the output the inner arrays of integers have not been sorted. What am I doing wrong? (PHP 5.5.9, Windows 7)

Use a reference &:
foreach ($data as $key => &$series)
{
//Sort array of integers
sort($series);
// OR
// sort($data[$key]);
}

Related

Cannot sort array of object by property name

I have this array:
$array = array(
['name' => 'Indor Swimming Pool'],
['name' => 'abracadabra'],
);
I want sort if alphabetically, so I did:
usort($array, function($a, $b)
{
return strcmp($a['name'], $b['name']);
});
but when I dump it:
var_dump($array);
I get:
array(2) {
[0]=>
array(1) {
["name"]=>
string(19) "Indor Swimming Pool"
}
[1]=>
array(1) {
["name"]=>
string(11) "abracadabra"
}
}
this is incorrect, abracadabra should go as first
According to the ASCII table chr I comes first and then comes the a chr
ASCII Table
So here your array is actually getting sorted alphabetically to achieve the desired result you need to sort the array in the descending order
<?php
$data = array(
['name' => 'Indor Swimming Pool'],
['name' => 'abracadabra'],
);
arsort($data);
?>
Output
Array
(
[1] => Array
(
[name] => abracadabra
)
[0] => Array
(
[name] => Indor Swimming Pool
)
)
It works as intended. The reason for this order is that 'a' is actually after 'I' in ASCII.

php sort by key multidimentional array

Supposed I have an array of
array(8) {
[0] =>
array(1) {
'Peter' =>
int(4)
}
[1] =>
array(1) {
'Piper' =>
int(4)
}
[2] =>
array(1) {
'picked' =>
int(4)
}
[3] =>
array(1) {
'peck' =>
int(4)
}
[4] =>
array(1) {
'pickled' =>
int(4)
}
How can I sort this multidimentional array by key example (Peter). I tried using
ksort($arr);
but it just return a boolean
The output that I want
array(8) {
[0] =>
array(1) {
'peck' =>
int(4)
}
[1] =>
array(1) {
'Peter' =>
int(4)
}
[2] =>
array(1) {
'picked' =>
int(4)
}
[3] =>
array(1) {
'pickled' =>
int(4)
}
[4] =>
array(1) {
'piper' =>
int(4)
}
the array should be sorted by key and in ascending order.
Sort with usort like this, check the demo
usort($array,function($a,$b){
return strcmp(strtolower(key($a)),strtolower(key($b)));
});
The ksort() method does an in-place sort. So while it only returns a boolean (as you correctly state), it mutates the values inside $arr to be in the sorted order. Note that based on your expected output, it looks like you want to do a case insensitive search. For that, you need to use the SORT_FLAG_CASE sort flag. So, instead of calling ksort($arr), you instead want to use ksort($arr, SORT_FLAG_CASE). You can see how ksort() uses sort flags, in the sort() method's documentation. Hope that helps!
You can do something like this,
$temp = array_map(function($a){
return key($a); // fetching all the keys
}, $arr);
natcasesort($temp); // sorting values case insensitive
$result = [];
// logic of sorting by other array
foreach($temp as $v){
foreach($arr as $v1){
if($v == key($v1)){
$result[] = $v1;
break;
}
}
}
Demo
Output
Array
(
[0] => Array
(
[peck] => 4
)
[1] => Array
(
[Peter] => 4
)
[2] => Array
(
[picked] => 4
)
[3] => Array
(
[pickled] => 4
)
[4] => Array
(
[Piper] => 4
)
)

PHP Multidimensional array - Remove part duplicates and add up

I have a multidimensional array like so:
array(4) {
[0] => array(2) {
[0] => string(15)
"One"
[1] => string(5)
"11:31"
}
[1] => array(2) {
[0] => string(4)
"Two"
[1] => string(5)
"11:31"
}
[2] => array(2) {
[0] => string(15)
"Three"
[1] => string(5)
"11:31"
}
[3] => array(2) {
[0] => string(4)
"One"
[1] => string(5)
"11:31"
}
}
I am trying to get the ones with the first value removed but added up together. So it would end up like so:
array(3) {
[0] => array(2) {
[0] => string(15)
"One"
[1] => string(5)
"22:62"
}
[1] => array(2) {
[0] => string(4)
"Two"
[1] => string(5)
"11:31"
}
[2] => array(2) {
[0] => string(15)
"Three"
[1] => string(5)
"11:31"
}
}
Note the last 'One' has been removed and the second value in the array has been added up there from two 11:31's to 22:62. I hope that makes sense.
Is there something or a specific function I should look at to push me in the right direction? Any help much appreciated.
This is not just a straight up removing duplicates from what I can tell, as none are ever exactly the same although the second values are in this example, they won't be in live data.
You could make a loop and group elements into a new array using key [0]. It the key doesn't exists in the new array, simply add the new array. Otherwise, you could parse the existing value to add the new value:
$array = [
["One", "11:31"],
["Two", "11:31"],
["Three", "11:31"],
["One", "11:31"],
];
$out = [];
foreach ($array as $item) {
// if $item[0] is not an existing key,
if (!isset($out[$item[0]])) {
// add $item as-is
$out[$item[0]] = $item;
} else {
// parse current time
list($h1, $m1) = explode(':', $item[1]);
$m1 += $h1 * 60;
// parse existing time
list($h2, $m2) = explode(':', $out[$item[0]][1]);
$m1 += $m2 + $h2 * 60;
// compute new time
$h = floor($m1 / 60);
$out[$item[0]][1] = sprintf("%02d:%02d", $h, $m1-$h*60);
}
}
// array_values removes 'named' keys.
print_r(array_values($out));
Output (condensed):
Array
(
[0] => Array ([0] => One [1] => 23:02)
[1] => Array ([0] => Two [1] => 11:31)
[2] => Array ([0] => Three [1] => 11:31)
)

PHP: Given a multidimensional array convert it into single dimensional sorted, sort of

Basically, I want to convert the below multidimensional array:
Array
(
[0] => Array
(
[0] => foo
[1] => bar
[2] => hello
)
[1] => Array
(
[0] => world
[1] => love
)
[2] => Array
(
[0] => stack
[1] => overflow
[2] => yep
[3] => man
)
)
Into this:
Array
(
[0] => foo
[1] => world
[2] => stack
[3] => bar
[4] => love
[5] => overflow
[6] => hello
[7] => yep
[8] => man
)
first element from first sub-array
first element from second sub-array, etc
second element from first sub-array
second element from second sub-array, etc...
So I've had a couple beers and I'll try and tighten this up later, but this does the trick for integer indexed arrays:
$result = array();
for($i=0; $c=array_column($array, $i); $i++) {
$result = array_merge($result, $c);
}
print_r($result);
Loop getting an array of columns starting with column 0 and increment the column number.
So long as there are columns, get an array of that column and merge with the result.
There is an often overlooked Iterator that will help you here: The MultipleIterator.
I have created some demo code: https://3v4l.org/beOMV
<?php
$arr = [
0 => [
0 => 'foo',
1 => 'bar',
2 => 'hello',
],
1 => [
0 => 'world',
1 => 'love',
],
2 => [
0 => 'stack',
1 => 'overflow',
2 => 'yep',
3 => 'man',
]
];
$parallelIterator = new MultipleIterator(MultipleIterator::MIT_NEED_ANY|MultipleIterator::MIT_KEYS_NUMERIC);
$parallelIterator->attachIterator(new ArrayIterator($arr[0]));
$parallelIterator->attachIterator(new ArrayIterator($arr[1]));
$parallelIterator->attachIterator(new ArrayIterator($arr[2]));
$result = [];
foreach ($parallelIterator as $values) {
foreach ($values as $value) {
if ($value !== null) {
$result[] = $value;
}
}
}
var_dump($result);
Essentially, iterating over the MultipleIterator will give you an array with all the first entries (and then second and so on) of ALL attached iterators in parallel. By using either MultipleIterator::MIT_NEED_ANY or MultipleIterator::MIT_NEED_ALL you can decide that the loop should stop either when the last iterator has no more elements, or when the first iterator runs out of elements. When you run until the last element of the last iterator, you'll get NULL instead.
When attaching iterators, you can also add a key that will be used in the array when iterating, and have to uses MultipleIterator::MIT_KEYS_ASSOC - I have simply used numeric indices here because the source of the particular array was not interesting.
The result is
array(9) {
[0]=> string(3) "foo"
[1]=> string(5) "world"
[2]=> string(5) "stack"
[3]=> string(3) "bar"
[4]=> string(4) "love"
[5]=> string(8) "overflow"
[6]=> string(5) "hello"
[7]=> string(3) "yep"
[8]=> string(3) "man"
}
Yes, you can iterate over that initial array when attaching the sub arrays to the MultipleIterator if you want:
foreach ($arr as $innerArr) {
$parallelIterator->attachIterator(new ArrayIterator($innerArr));
}

Remove similar objects from array?

I have an array of objects, but I need to remove a similar objects by a few properties from them:
for example:
array(12) {
[0]=>
object(stdClass)#848 (5) {
["variant"]=>
object(stdClass)#849 (4) {
["name"]=>
string(8) "Alex"
}
["age"]=>
int(10)
}
[1]=>
object(stdClass)#851 (5) {
["variant"]=>
object(stdClass)#852 (4) {
["name"]=>
string(8) "Alex"
}
["age"]=>
int(10)
}
How to make a one object in array for this ( if for example I need to compare only by a name property? )
Still have an issue with it.
Updated
I've create a new array of objects:
$objects = array(
(object)array('name'=>'Stiven','age'=>25,'variant'=>(object)array('surname'=>'Sigal')),
(object)array('name'=>'Michael','age'=>30,'variant'=>(object)array('surname'=>'Jackson')),
(object)array('name'=>'Brad','age'=>35,'variant'=>(object)array('surname'=>'Pit')),
(object)array('name'=>'Jolie','age'=>35,'variant'=>(object)array('surname'=>'Pit')),
);
echo "<pre>";
print_r($objects);
So what I need to do is to compare an object properties (variant->surnames and ages), if two objects has a similar age and variant->surname we need to remove the one of these objects.
A half of solution is:
$tmp = array();
foreach ($objects as $item=>$object)
{
$tmp[$object->variant->surname][$object->age] = $object;
}
print_r($tmp);
Unfortunatelly I need an old-style array of objects.
I've found an example.
<?php
$a = array (
0 => array ( 'value' => 'America', ),
1 => array ( 'value' => 'England', ),
2 => array ( 'value' => 'Australia', ),
3 => array ( 'value' => 'America', ),
4 => array ( 'value' => 'England', ),
5 => array ( 'value' => 'Canada', ),
);
$tmp = array ();
foreach ($a as $row)
if (!in_array($row,$tmp)) array_push($tmp,$row);
print_r ($tmp);
?>
Quoted from here

Categories