php sort by key multidimentional array - php

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
)
)

Related

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)
)

Enhancing asort by order of keys

I am using asort to sort the numeric array. For e.g.
$arr = [0,1,1,2,1,2,2,3];
After running asort I am getting:
Array
(
[0] => 0
[4] => 1
[2] => 1
[1] => 1
[6] => 2
[3] => 2
[5] => 2
[7] => 3
)
But I am expecting to get it in this order:
Array
(
[0] => 0
[1] => 1
[2] => 1
[4] => 1
[3] => 2
[5] => 2
[6] => 2
[7] => 3
)
See the difference in order of the keys above.
First sort the array.
Then generate an array by flipping in a way so that the keys can be separated according to values. Sort the arrays with keys and merge them to an array. And the combine the keys with the sorted values.
$arr = [0,1,1,2,1,2,2,3];
asort($arr);
$sorted = $arr;
$flipped = $new_keys = array();
foreach($arr as $key => $val) {
$flipped[$val][] = $key; // Get the keys
}
foreach($flipped as $key => $val_array) {
asort($val_array); // Sort the keys
$new_keys = array_merge($new_keys, $val_array);
}
$final = array_combine($new_keys, $sorted); // Combine them again
var_dump($final);
Output
array(8) {
[0]=>
int(0)
[1]=>
int(1)
[2]=>
int(1)
[4]=>
int(1)
[3]=>
int(2)
[5]=>
int(2)
[6]=>
int(2)
[7]=>
int(3)
}
This should work for you:
First walk through each array value with array_walk() and change each value to an array containing the value and the key.
After this use uasort() to sort your array and if both values are the same you use the key to choose which one should be first.
At the end just use array_column() to transform your array back.
<?php
$arr = [0,1,1,2,1,2,2,3];
array_walk($arr, function(&$v, $k){
$v = ["value" => $v, "key" => $k];
});
uasort($arr, function($a, $b){
if($a["value"] == $b["value"]) {
if($a["key"] == $b["key"])
return 0;
return $a["key"] > $b["key"] ? 1 : -1;
}
return $a["value"] > $b["value"] ? 1 : -1;
});
$arr = array_column($arr, "value", "key");
print_r($arr);
?>
output:
Array
(
[0] => 0
[1] => 1
[2] => 1
[4] => 1
[3] => 2
[5] => 2
[6] => 2
[7] => 3
)

PHP - sort arrays within assoc array

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]);
}

How to get rid of duplicate values from multidimensional array

I want to remove duplicate values from multi-dim array, I tried all the possible solutions which is already described but for me, is not working, can anyone please correct it?
Here's my Array:
Array (
[0] => Array (
[0] => element_10
[1] => block_1
[2] => element_4
[3] => element_1
[4] => element_3
)
[1] => Array (
[0] => block_1
[1] => block_2
[2] => element_8
[3] => element_10
[4] => element_12
[5] => element_14
[6] => element_4
[7] => element_2
[8] => element_3
[9] => element_9
[10] => element_13
[11] => element_7
)
)
Where I want the array in this format:
Array (
[0] => Array (
[0] => element_10
[1] => block_1
[2] => element_4
[3] => element_1
[4] => element_3
)
[1] => Array (
[1] => block_2
[2] => element_8
[4] => element_12
[5] => element_14
[7] => element_2
[9] => element_9
[10] => element_13
[11] => element_7
)
)
Ican setup the key indexes later.
I tried:
function multi_unique($array) {
foreach ($array as $k=>$na)
$new[$k] = serialize($na);
$uniq = array_unique($new);
foreach($uniq as $k=>$ser)
$new1[$k] = unserialize($ser);
return ($new1);
}
No Luck, then I tried:
function array_unique_multidimensional($input)
{
$serialized = array_map('serialize', $input);
$unique = array_unique($serialized);
return array_intersect_key($input, $unique);
}
Still same array returning.
I tried this method too:
function super_unique($array)
{
$result = array_map("unserialize", array_unique(array_map("serialize", $array)));
foreach ($result as $key => $value)
{
if ( is_array($value) )
{
$result[$key] = self::super_unique($value);
}
}
return $result;
}
Please help me, I know it's pretty simple I don't know where I'm losing?
Thanks,
You need to iterate over your list of input arrays. For each value in that array, you need to see if you've previously encountered it, so you'll have to keep a super-set of all values across all arrays, which you gradually append to. If a value already exists in the super-set array, you can remove it, otherwise you can append it.
function multi_unique($arrays) {
$all_values = array();
foreach ($arrays as &$array) {
foreach ($array as $index => $value) {
if (in_array($value, $all_values)) {
// We've seen this value previously
unset($array[$index]);
} else {
// First time we've seen this value, let it pass but record it
$all_values[] = $value;
}
}
}
return $arrays;
}
$values = array (
array ( 'element_10', 'block_1', 'element_4', 'element_1', 'element_3',) ,
array ( 'block_1', 'block_2', 'element_8', 'element_10', 'element_12', 'element_14', 'element_4', 'element_2', 'element_3', 'element_9', 'element_13', 'element_7',)
);
var_dump(multi_unique($values));
Output:
array(2) {
[0]=>
array(5) {
[0]=>
string(10) "element_10"
[1]=>
string(7) "block_1"
[2]=>
string(9) "element_4"
[3]=>
string(9) "element_1"
[4]=>
string(9) "element_3"
}
[1]=>
array(8) {
[1]=>
string(7) "block_2"
[2]=>
string(9) "element_8"
[4]=>
string(10) "element_12"
[5]=>
string(10) "element_14"
[7]=>
string(9) "element_2"
[9]=>
string(9) "element_9"
[10]=>
string(10) "element_13"
[11]=>
string(9) "element_7"
}
}
If you just want to remove duplicates from the second entry of your array, use array_diff():
$array[1] = array_diff($array[1], $array[0]);
Iterate if you want to apply it to an arbitrary length.
Why are you using the serialize function.
Use array_diff instead.
A simple would be.
$orginal = array(array(values), array(values), ...);
$copy = $original;
foreach($original as $k => $subArray) {
$tmpCopy = $copy;
unset($tmpCopy[$k]);
unshift($tmpCopy, $subArray);
$tmpCopy = array_values($tmpCopy);
$original[$k] = call_user_func_array('array_diff', $tmpCopy);
}
This works for a two dimensions array.
Hope it helps.

Recreate Multidimensional Array in PHP

This is pretty basic, but my question is:
Given an array:
$a = array(
0 => array('Rate'=> array('type_id'=>1, 'name' => 'Rate_1', 'type'=>'day','value'=>10)),
1 => array('Rate'=> array('type_id'=>1, 'name' => 'Rate_2', 'type'=>'night','value'=>8)),
2 => array('Rate'=> array('type_id'=>2, 'name' => 'Rate_3', 'type'=>'day','value'=>7)),
3 => array('Rate'=> array('type_id'=>2, 'name' => 'Rate_4', 'type'=>'nigh','value'=>16)),
4 => array('Rate'=> array('type_id'=>3, 'name' => 'Rate_5', 'type'=>'day','value'=>10))
);
What is the most efficient way to change it so we have something like:
$new_array = array(
[type_id] => array(
[type] => array(
[value]
)
)
)
);
In other words, I would like to strip some data (the name, which I don't need) and reorganise the dimensions of the array. In the end I would have an array which I would be able to access the values by $new_array['type_id']['type']['value'].
Not entirely sure if this is exactly what you want, but with this you can access the values by saying
echo $new[TYPE_ID][DAY_OR_NIGHT];
$new = array();
foreach($a AS $b){
$c = $b['Rate'];
$new[$c['type_id']][$c['type']] = $c['value'];
}
Using print_r on $new would give you:
Array
(
[1] => Array
(
[day] => 10
[night] => 8
)
[2] => Array
(
[day] => 7
[night] => 16
)
[3] => Array
(
[day] => 10
)
)
Since php 5.3.0, array_reduce() allows using an array as the initial value, given your initial array $a, you can use the following code
function my_reducer ($result, $item) {
$result[$item['Rate']['type_id']][$item['Rate']['type']] = $item['Rate']['value'];
return $result;
}
$assoc_arr = array_reduce($a, 'my_reducer', array());
var_dump($assoc_arr);
This returns
array(3) { [1]=> array(2) {
["day"]=>
int(10)
["night"]=>
int(8) } [2]=> array(2) {
["day"]=>
int(7)
["nigh"]=>
int(16) } [3]=> array(1) {
["day"]=>
int(10) } }

Categories