Sorting array by count of subarray - php

I have an array looking like this:
Array(
['some_first_category'] => Array(
['some_first_name'] => Array(
[0]=>'first#email.com',
[1]=>'second#email.com',
[2]=>'third#email.com',
[3]=>'fourth#email.com' )
['some_second_name'] => Array (
[1]=>'first#email.com',
[2]=>'second#email.com')
['some_third_name'] => Array(
[1]=>'first#email.com',
[2]=>'second#email.com',
[3]=>'third#email.com',
[4]=>'fourth#email.com' )
['some_second_category'] => Array(
['some_first_name'] => Array(
[0]=>'first#email.com' )
['some_second_name'] => Array(
[1]=>'first#email.com',
[2]=>'second#email.com',
[3]=>'third#email.com',
[4]=>'fourth#email.com')
['some_third_name'] => Array(
[1]=>'first#email.com',
[2]=>'second#email.com'))
And I want to sort the array by the number of values of that has the names, In my case I want to become this array:
Array(
['some_first_category'] => Array(
['some_third_name'] => Array(
[1]=>'first#email.com',
[2]=>'second#email.com',
[3]=>'third#email.com',
[4]=>'fourth#email.com' )
['some_first_name'] => Array(
[0]=>'first#email.com',
[1]=>'second#email.com',
[2]=>'third#email.com',
[3]=>'fourth#email.com' )
['some_second_name'] => Array (
[1]=>'first#email.com',
[2]=>'second#email.com')
['some_second_category'] => Array(
['some_second_name'] => Array(
[1]=>'first#email.com',
[2]=>'second#email.com',
[3]=>'third#email.com',
[4]=>'fourth#email.com')
['some_third_name'] => Array(
[1]=>'first#email.com',
[2]=>'second#email.com')
['some_first_name'] => Array(
[0]=>'first#email.com' ))
This means sorting categories by name by the number(count) of values of the names. Someone can help me?
Thanks in advance,
Aäron

All you need is uasort
uasort($list, function ($a, $b) {
$a = count($a);
$b = count($b);
return ($a == $b) ? 0 : (($a < $b) ? -1 : 1);
});
Full Example
$list = Array(
'some_first_category' => Array(
'some_first_name' => Array(
0=>'first#email.com',
1=>'second#email.com',
2=>'third#email.com',
3=>'fourth#email.com' ),
'some_second_name' => Array (
1=>'first#email.com',
2=>'second#email.com'),
'some_third_name' => Array(
1=>'first#email.com',
2=>'second#email.com',
3=>'third#email.com',
4=>'fourth#email.com' )
),
'some_second_category' => Array(
'some_first_name' => Array(
0=>'first#email.com' ),
'some_second_name' => Array(
1=>'first#email.com',
2=>'second#email.com',
3=>'third#email.com',
4=>'fourth#email.com'),
'some_third_name' => Array(
1=>'first#email.com',
2=>'second#email.com'))
);
$list = array_map(function ($v) {
uasort($v, function ($a, $b) {
$a = count($a);
$b = count($b);
return ($a == $b) ? 0 : (($a < $b) ? 1 : - 1);
});
return $v;
}, $list);
print_r($list);
Output
Array
(
[some_first_category] => Array
(
[some_first_name] => Array
(
[0] => first#email.com
[1] => second#email.com
[2] => third#email.com
[3] => fourth#email.com
)
[some_third_name] => Array
(
[1] => first#email.com
[2] => second#email.com
[3] => third#email.com
[4] => fourth#email.com
)
[some_second_name] => Array
(
[1] => first#email.com
[2] => second#email.com
)
)
[some_second_category] => Array
(
[some_second_name] => Array
(
[1] => first#email.com
[2] => second#email.com
[3] => third#email.com
[4] => fourth#email.com
)
[some_third_name] => Array
(
[1] => first#email.com
[2] => second#email.com
)
[some_first_name] => Array
(
[0] => first#email.com
)
)
)

Using uksort:
uksort($yourArray, function($a, $b) { return count($b) - count($a); });
Using array_multisort:
array_multisort(array_map('count', $yourArray), SORT_DESC, $yourArray);
and you can see uasort as well
best of luck :)

You should use usort function. Refer here.
function sort_sub($a,$b)
{
$res= count($b)-count($a);
return $res;
}
usort($array_name,'sort_sub')

Related

merge 2 array with different number of keys

I have 2 arrays
$arr1 = Array
(
[REG1] => 94
[REG3] => 45
)
$arr2 =Array
(
[0] => REG1
[1] => REG2
[2] => REG3
[3] => REG4
)
I have to loop 2 arrays and I would like a result in one array like this:
Array(
[0] => Array(
[REG1] => 94
)
[1] => Array(
[REG2] =>
)
[2] => Array(
[REG3] => 45
)
[3] => Array(
[REG4] =>
)
)
But for the instand I can not do what I want, here is where I am:
private function mergeData($arr1, $arr2){
$result = array_map(function($v1, $v2){
$t[$v1] = $v2;
return $t;
}, $arr2, $arr1);
return $result;
}
output:
Array(
[0] => Array(
[REG1] => 94
)
[1] => Array(
[REG2] =>45
)
[2] => Array(
[REG3] =>
)
[3] => Array(
[REG4] =>
)
)
I cannot correctly put the bone values with the right keys.
I tried with array_merge_recursive but also failed.
Thanks for your help
$arr3 = array_fill_keys( $arr2, '' );
creates an array containing the values of $arr2 as keys with as value an empty string.
$arr3 =Array
(
[REG1] => ''
[REG2] => ''
[REG3] => ''
[REG4] => ''
)
After that just merge.
$result = array_merge ( $arr3, $arr1 );
Another option would be to use the array_map function and map key with the corresponding values, if any:
$arr1 = [
'REG1' => 94,
'REG3' => 45
];
$arr2 = [
'REG1',
'REG2',
'REG3',
'REG4'
];
$result = array_map(function($item) use($arr1){
return [$item => isset($arr1[$item]) ? $arr1[$item] : ""];
},$arr2);
This will return:
Array
(
[0] => Array
(
[REG1] => 94
)
[1] => Array
(
[REG2] =>
)
[2] => Array
(
[REG3] => 45
)
[3] => Array
(
[REG4] =>
)
)
Using a loop:
<?php
$arr1 = [
'REG1' => 94,
'REG3' => 45
];
$arr2 = [
'REG1',
'REG2',
'REG3',
'REG4'
];
$result = $arr2;
foreach($result as &$v)
$v = [$v => $arr1[$v] ?? null];
unset($v);
var_export($result);
Output:
array (
0 =>
array (
'REG1' => 94,
),
1 =>
array (
'REG2' => NULL,
),
2 =>
array (
'REG3' => 45,
),
3 =>
array (
'REG4' => NULL,
),
)

PHP - Order array associative by specific value

I'm looking for a way to order an array associative by a specific value, I'm not sure if it's possible. I tried it with array_multisort() and usort() functions, but I'm afraid that I can not get it.
Example:
$array[] = array('id' => 74215, 'type' => 'BOX');
$array[] = array('id' => 76123, 'type' => 'UNT');
$array[] = array('id' => 71231, 'type' => '');
$array[] = array('id' => 79765, 'type' => 'UNT');
$array[] = array('id' => 77421, 'type' => 'BOX');
If I want to order by 'BOX', then the array will be:
Array (
[0] => Array
(
[id] => 77421
[type] => 'BOX'
)
[1] => Array
(
[id] => 74215
[type] => 'BOX'
)
[2] => Array
(
[id] => 76123
[type] => 'UNT'
)
.
.
.
I could pass other string like 'UNT', and order by like that.
Is this possible??
I assume you want to "sort" by string match, first all those who match that string, after that all those that don't. Unless you have an archaic php version, this could work:
$sortvalue = 'BOX';
usort($array, function($a, $b) use ($sortvalue) {
if($a['type'] == $sortvalue) return -1;
elseif($b['type'] == $sortvalue) return 1;
else return 0;
});
this should put any 'BOX' entry to the front of your array.
If all others shall be grouped, instead of return 0 do return $a['type'] < $b['type'].
edit: integrated kamal pal's suggestion/correction
I'm not sure if PHP has it's own function that does that, but i write my own, hope it helps:
function sortArray($array_x, $key)
{
$added_indexes;
$new_array;
for($i=0;$i<count($array_x);$i++)
{
if($array_x[$i]['type']==$key){
$new_array[]=$array_x[$i];
$added_indexes[]=$i;
}
}
for($i=0;$i<count($array_x);$i++)
{
if(!in_array($i,$added_indexes))
{
$new_array[]=$array_x[$i];
}
}
return $new_array;
}
So when you do this:
$array[] = array('id' => 74215, 'type' => 'BOX');
$array[] = array('id' => 76123, 'type' => 'UNT');
$array[] = array('id' => 71231, 'type' => '');
$array[] = array('id' => 79765, 'type' => 'UNT');
$array[] = array('id' => 77421, 'type' => 'BOX');
print_r(sortArray($array,"BOX"));
Gives this:
Array
(
[0] => Array
(
[id] => 74215
[type] => BOX
)
[1] => Array
(
[id] => 77421
[type] => BOX
)
[2] => Array
(
[id] => 76123
[type] => UNT
)
[3] => Array
(
[id] => 71231
[type] =>
)
[4] => Array
(
[id] => 79765
[type] => UNT
)
)
Yeah I was thinking in a similar solution:
usort($array, function ($a, $b) {
return $a['type'] == 'BOX' ? -1 : ($b['type'] == 'BOX' ? 1 : 0);
});

Problems with sorting multidimensional array

I try to sort a multidimensional array in the way, so that the elements with the same value should not being reordered.
This is the given array, which should be sorted by the value of type:
$arr = array(
"a" => array(
"type" => 1
),
"d" => array(
"type" => 1
),
"super" => array(
"type" => 2
),
"c" => array(
"type" => 1
),
"b" => array(
"type" => 1
)
);
The sorted array should be look like this:
Array
(
[super] => Array
(
[type] => 2
)
[a] => Array
(
[type] => 1
)
[d] => Array
(
[type] => 1
)
[c] => Array
(
[type] => 1
)
[b] => Array
(
[type] => 1
)
)
I want to improve your own answer to exclude inefficient array_search(). It is better to index array items before sorting, and use it for equal types.
$index = 0;
foreach ($arr as $key => $value) {
$arr[$key]['index'] = $index;
$index++;
}
uasort($arr, function($a, $b) {
if ($a['type'] < $b['type']) {
return 1;
} elseif ($a['type'] > $b['type']) {
return -1;
} else {
return $a['index'] - $b['index'];
}
});
foreach ($arr as $key => $value) {
unset($arr[$key]['index']);
}
Try a uasort: If you are still on PHP 5.2 or earlier, you'll have to define a sorting function first:
$myArray = array(
"a" => array(
"type" => 1
),
"d" => array(
"type" => 1
),
"super" => array(
"type" => 2
),
"c" => array(
"type" => 1
),
"b" => array(
"type" => 1
)
);
function sortByOrder($a, $b)
{
return $b['type'] - $a['type'];
}
uasort($myArray, 'sortByOrder');
print_r($myArray);
Starting in PHP 5.3, you can use an anonymous function:
uasort($myArray, function ($a, $b) {
return $b['type'] - $a['type'];
});
And finally with PHP 7 you can use the "spaceship operator":
uasort($myArray, function ($a, $b) {
return $b['type'] <=> $a['type'];
});
Output:
Array
(
[super] => Array
(
[type] => 2
)
[b] => Array
(
[type] => 1
)
[c] => Array
(
[type] => 1
)
[a] => Array
(
[type] => 1
)
[d] => Array
(
[type] => 1
)
)
After browsing through the post (How can I sort arrays and data in PHP?)[How can I sort arrays and data in PHP?, I found a solution for my problem.
If the types are equal, I sort the elements into a static order, which I get from a second value id.
Array to sort:
$array = array(
"a" => array(
"id" => "a",
"type" => 1
),
"c" => array(
"id" => "c",
"type" => 1
),
"super" => array(
"id" => "super",
"type" => 2
),
"b" => array(
"id" => "b",
"type" => 1
)
);
Script:
$sort_keys = array_column($array, "id");
function cmp($a, $b){
global $sort_keys;
if ($a["type"] < $b["type"]) {
return 1;
} else if ($a["type"] > $b["type"]) {
return -1;
} else {
return array_search($a["_id"], $sort_keys) - array_search($b["_id"], $sort_keys);
}
}
uasort($array, 'cmp');
I do have the field id in my script already, so I don’t even have to change my array.
Thanks to all who contribute to this post!

merge arrays where some value of parent arrays is not equals

I array of arrays, what look something like that:
$messages = array (
0 =>
array(
'keyT' => 'id.key'
'mess' => array(
array(1,0)
)
...
)
I want to merge mess preperties of arrays where 'keyT' is not equals.
I run trought the arrays:
foreach ($messages as $k => $current) {
foreach ($messages as $ke => $all) {
if ($current['keyT'] == $all['keyT']) {
array_merge( ... )
}
}
}
But this not deve me any results. Maybe somebody can help me. Thanks!
Try this code
$messages = array(
0 =>
array(
'keyT' => 'A',
'mess' => array(
array(1, 0)
)
),
1 =>
array(
'keyT' => 'A',
'mess' => array(
array(1, 2)
)
),
2 =>
array(
'keyT' => 'B',
'mess' => array(
array(3, 4)
)
)
);
$result = array();
foreach ($messages as $msg) {
$key = $msg['keyT'];
if (!isset($result[$key])) {
$result[$key] = array();
}
$result[$key] = array_merge($result[$key], $msg['mess']);
}
print_r($result);
Output
Array
(
[A] => Array
(
[0] => Array
(
[0] => 1
[1] => 0
)
[1] => Array
(
[0] => 1
[1] => 2
)
)
[B] => Array
(
[0] => Array
(
[0] => 3
[1] => 4
)
)
)

PHP sort array using specific letter

I have an php array like below:
Array (
[0] => Array ( [value] => 5 [label] => Akon )
[1] => Array ( [value] => 6 [label] => Angel )
[2] => Array ( [value] => 7 [label] => Britny )
[3] => Array ( [value] => 9 [label] => Mark Anthony )
[4] => Array ( [value] => 8 [label] => Michel )
[5] => Array ( [value] => 4 [label] => Shaggy )
[6] => Array ( [value] => 3 [label] => Smith )
)
I need this array sort by specific letter. For example, if I sort by this "M" letter array should look like below.
Array (
[3] => Array ( [value] => 9 [label] => Mark Anthony )
[4] => Array ( [value] => 8 [label] => Michel )
[6] => Array ( [value] => 3 [label] => Smith )
[0] => Array ( [value] => 5 [label] => Akon )
[1] => Array ( [value] => 6 [label] => Angel )
[2] => Array ( [value] => 7 [label] => Britny )
[5] => Array ( [value] => 4 [label] => Shaggy )
)
The begging letter should comes to first of array.(here begin with m)
I greatly appreciated your any kind of help. Thank you very much...
Your comparison logic is going to be like this:
if two strings A and B start with the same letter, compare them as usual
if A starts with 'M', A wins
if B starts with 'M', B wins
otherwise, compare as usual
in code
$strings = array('Foo', 'Moo', 'Xuux', 'Me', 'Blah', 'Ma');
$letter = 'M';
usort($strings, function($a, $b) use($letter) {
if($a[0] != $b[0]) {
if($a[0] == $letter) return -1;
if($b[0] == $letter) return +1;
}
return strcmp($a, $b);
});
print_r($strings);
class Cmp {
public $letter;
function __construct( $letter ) { $this->letter = $letter; }
function doCmp( $a, $b ) {
if( $a['label'][0] == $this->letter ) {
if( $b['label'][0] != $this->letter ) return -1;
} else {
if( $b['label'][0] == $this->letter ) return 1;
}
return $a['label'] > $b['label'] ? 1 : -1;
}
}
usort( $arr, array( new Cmp( 'M' ), 'doCmp' ) );
$strings = array (
array ( 'value' => 5, 'label' => 'Akon' ),
array ( 'value' => 6, 'label' => 'Angel' ),
array ( 'value' => 7, 'label' => 'Britny' ),
array ( 'value' => 9, 'label' => 'Mark Anthony' ) ,
array ( 'value' => 8, 'label' => 'Michel' ) ,
array ( 'value' => 4, 'label' => 'Shaggy' ) ,
array ( 'value' => 3, 'label' => 'Smith' )
) ;
var_dump($strings);
$letter = 'm';
usort ($strings, function ($left, $right) {
return ((($posLeft = strpos(strtolower($left['label']), 'm')) === false)
? PHP_INT_MAX
: $posLeft)
- ((($posRight = strpos(strtolower($right['label']), 'm')) === false)
? PHP_INT_MAX
: $posRight);
});
var_dump($strings);
Just compares the position of the letter within the two strings. If the letter is not within one of the strings (strpos() returns false), it assumes an "infinite" index (PHP_INT_MAX),
this is an example i found on php.net that could help you and maintain the index : http://www.php.net/manual/en/function.sort.php#99419
Sort the data by the value based on the comparison reflecting the letter (Demo):
<?php
# the data
$data = array(
0 => array(
'value' => 5,
'label' => 'Akon',
),
1 => array(
'value' => 6,
'label' => 'Angel',
),
2 => array(
'value' => 7,
'label' => 'Britny',
),
3 => array(
'value' => 9,
'label' => 'Mark Anthony',
),
4 => array(
'value' => 8,
'label' => 'Michel',
),
5 => array(
'value' => 4,
'label' => 'Shaggy',
),
6 => array(
'value' => 3,
'label' => 'Smith',
),
);
# the letter
$letter = 'M';
# the value to compare against
$value = function(array $a)
{
$key = 'label';
if (!array_key_exists($key, $a))
{
throw new InvalidArgumentException(sprintf('Key "%s" missing.', $key));
}
return $a[$key];
};
# the comparison
$compare = function($a, $b) use ($letter, $value)
{
$a = $value($a);
$b = $value($b);
if($a[0] != $b[0]) {
if($a[0] === $letter) return -1;
if($b[0] === $letter) return +1;
}
return strcmp($a, $b);
};
# the sort
$sort = function() use ($data, $compare)
{
$r = uasort($data, $compare);
if (!$r)
{
throw new RuntimeException('Sort failed.');
}
return $data;
};
print_r($sort());
Use usort to sort by a function. The function can contain any logic you want to put in, as long as the return value indicates sort order (see link for details).

Categories