$data = array(
'apple' => array(
0 => array('sort'=>4, 'name'=>'apple_4'),
1 => array('sort'=>10, 'name'=>'apple_10'),
2 => array('sort'=>5, 'name'=>'apple_5'),
3 => array('sort'=>1, 'name'=>'apple_1')
),
'orange' => array(
0 => array('sort'=>4, 'name'=>'orange_4'),
1 => array('sort'=>10, 'name'=>'orange_10')
)
);
Need assistance sorting multi-dimensional array. For the array above, I would like to sort the contents of each group in descending order by the 'sort' value. The group's keys should remain in tact (apple, orange) but content's keys are not important.
Data should be ordered:
apple
apple_10
apple_5
apple_4
apple_1
orange
orange_10
orange_4
Use usort() to sort the array:
foreach($data as &$value) {
usort($value,function($a,$b) {
return $b['sort'] - $a['sort'];
});
}
$data = array(
'apple' => array(
0 => array('sort'=>4, 'name'=>'apple_4'),
1 => array('sort'=>10, 'name'=>'apple_10'),
2 => array('sort'=>5, 'name'=>'apple_5'),
3 => array('sort'=>1, 'name'=>'apple_1')
),
'orange' => array(
0 => array('sort'=>4, 'name'=>'orange_4'),
1 => array('sort'=>10, 'name'=>'orange_10')
)
);
foreach($data as &$value) {
usort($value, function($a, $b) {
return $a['sort'] < $b['sort'];
});
}
Related
I have this array :
(
[id] => block_5df755210d30a
[name] => acf/floorplans
[data] => Array
(
[floorplans_0_valid_for_export] => 0
[floorplans_0_title] => title 1
[floorplans_0_house_area] => 40m²
[floorplans_0_bedrooms] => 1
[floorplans_1_valid_for_export] => 1
[floorplans_1_title] => title xx
[floorplans_1_house_area] => 90m²
[floorplans_1_bedrooms] => 2
[floorplans_2_valid_for_export] => 1
[floorplans_2_title] => title 2
[floorplans_2_house_area] => 50m²
[floorplans_2_bedrooms] => 1
[floorplans] => 3
)
)
As we can see in the data, we have fields (floorplans_X_valid_for_export).
What I want to do is to get the data only when this field equal to 1.
So from the given example, I want to keep only these fields:
[floorplans_1_valid_for_export] => 1
[floorplans_1_title] => title xx
[floorplans_1_house_area] => 90m²
[floorplans_1_bedrooms] => 2
[floorplans_2_valid_for_export] => 1
[floorplans_2_title] => title 2
[floorplans_2_house_area] => 50m²
[floorplans_2_bedrooms] => 1
This is an odd schema, but it can be done by iterating through the array and searching for keys where "valid_for_export" equals 1, and then using another array of field "stubs" to get the associated items by a unique identifier of X in floorplans_X_valid_for_export
$array = [
'floorplans_0_valid_for_export' => 0,
'floorplans_0_title' => 'title 1',
'floorplans_0_house_area' => '40m²',
'floorplans_0_bedrooms' => 1,
'floorplans_1_valid_for_export' => 1,
'floorplans_1_title' => 'title xx',
'floorplans_1_house_area' => '90m²',
'floorplans_1_bedrooms' => '2',
'floorplans_2_valid_for_export' => 1,
'floorplans_2_title' => 'title 2',
'floorplans_2_house_area' => '50m²',
'floorplans_2_bedrooms' => 1,
'floorplans' => 3
];
$stubs = [
'floorplans_%s_valid_for_export',
'floorplans_%s_title',
'floorplans_%s_house_area',
'floorplans_%s_bedrooms'
];
$newArr = [];
foreach ($array as $key => $value) {
if (strpos($key, 'valid_for_export') && $array[$key] == 1) {
$intVal = filter_var($key, FILTER_SANITIZE_NUMBER_INT);
foreach ($stubs as $stub) {
$search = sprintf($stub, $intVal);
if (isset($array[$search])) {
$newArr[$search] = $array[$search];
} else {
// key can't be found, generate one with null
$newArr[$search] = null;
}
}
}
}
echo '<pre>';
print_r($newArr);
Working: http://sandbox.onlinephpfunctions.com/code/23a225e3cefa2dc9cc97f53f1cbae0ea291672c0
Use a parent loop to check that the number-specific valid_for_export value is non-empty -- since it is either 0 or non-zero.
If so, then just push all of the associated elements into the result array.
Some reasons that this answer is superior to the #Alex's answer are:
Alex's parent loop makes 13 iterations (and the same number of strpos() calls); mine makes just 3 (and only 3 calls of empty()).
$array[$key] is more simply written as $value.
Sanitizing the $key to extract the index/counter is more overhead than necessary as demonstrated in my answer.
Code (Demo)
$array = [
'floorplans_0_valid_for_export' => 0,
'floorplans_0_title' => 'title 1',
'floorplans_0_house_area' => '40m²',
'floorplans_0_bedrooms' => 1,
'floorplans_1_valid_for_export' => 1,
'floorplans_1_title' => 'title xx',
'floorplans_1_house_area' => '90m²',
'floorplans_1_bedrooms' => '2',
'floorplans_2_valid_for_export' => 1,
'floorplans_2_title' => 'title 2',
'floorplans_2_house_area' => '50m²',
'floorplans_2_bedrooms' => 1,
'floorplans' => 3
];
$labels = ['valid_for_export', 'title', 'house_area', 'bedrooms'];
$result = [];
for ($i = 0; $i < $array['floorplans']; ++$i) {
if (!empty($array['floorplans_' . $i . '_valid_for_export'])) {
foreach ($labels as $label) {
$key = sprintf('floorplans_%s_%s', $i, $label);
$result[$key] = $array[$key];
}
}
}
var_export($result);
Output:
array (
'floorplans_1_valid_for_export' => 1,
'floorplans_1_title' => 'title xx',
'floorplans_1_house_area' => '90m²',
'floorplans_1_bedrooms' => '2',
'floorplans_2_valid_for_export' => 1,
'floorplans_2_title' => 'title 2',
'floorplans_2_house_area' => '50m²',
'floorplans_2_bedrooms' => 1,
)
With that constructed data it might be hard (not impossble tho), hovewer i would suggest to change it to multidimensional arrays so you have something like:
[floorplans][0][valid_for_export] => 0
[floorplans][0][title] => title 1
[floorplans][0][house_area] => 40m²
[floorplans][0][bedrooms] => 1
[floorplans][1][valid_for_export] => 1
[floorplans][1][title] => title xx
[floorplans][1][house_area] => 90m²
Rought sollution
It is not the best approach, but it should work if you dont need anything fancy, and know that structure of data wont change in future
$keys = [];
$for($i=0;$i<$array['floorplans'];++$i) {
if(isset($array['floorplans_'.$i.'_valid_for_export']) && $array['floorplans_'.$i.'_valid_for_export']===1) {
$keys[] = $i;
}
}
print_r($keys);
This question already has answers here:
Sorting a php array of arrays by custom order
(8 answers)
Closed 28 days ago.
I have array $data containing data about animals. I would like to sort this array by child element:
source array ($data):
Array (
[0] => (
'name' => 'Leo'
'type' => 'cat'
)
[1] => (
'name' => 'Max'
'type' => 'dog'
)
[2] => (
'name' => 'Elsa'
'type' => 'fish'
)
...
)
priority array ($priority)
$priority = [
'fish', 'dog', 'cat',
];
I would like to sort source array using priority array. I tried:
sort($data, function (int $item1, int $item2) use($priority) {
foreach($priority as $key => $value) {
if($item1 == $value)
{
return 0;
break;
}
if($item2 == $value)
{
return 1;
break;
}
}
return 0;
});
You can use usort with a custom compare function, like so:
<?php
$arr = array(
0 => array(
'name' => 'Leo',
'type' => 'cat'
),
1 => array(
'name' => 'Max',
'type' => 'dog'
),
2 => array(
'name' => 'Elsa',
'type' => 'fish'
)
);
$priority = array('fish', 'dog', 'cat');
usort($arr, function($a, $b) use($priority) {
return array_search($a['type'], $priority) <=> array_search($b['type'], $priority);
});
var_dump($arr);
How this works:
usort accepts a custom compare function, you can pass it the priority array, then use the spaceship operator to compare the value indexes in priority.
Try it out: http://sandbox.onlinephpfunctions.com/code/03fdfa61b1bd8b0b84e5f08ab11b6bc90eeaef4a
I would like to merge two arrays recursively, leaving associative keys in place, but replace other. I tried using is_numeric() for key checking, but keys '10' and '11' are replaced.
Sample arrays:
Array1:
$arr1['assoc']='foobar';
$arr1[]='test index';
$arr1[][]=array(3,4);
$arr1['10']['test10'][]=array(0,1);
$arr1['11']['test11']=45;
$arr1['multiarray'][]=array(0,1);
Array2:
$arr2[]=1;
$arr2[][]=2;
$arr2['assoc']='test passed';
$arr2['10']['test10'][]=array(0,2);
$arr2['11']['test11']=array(4,5);
$arr2['multiarray'][]=array(0,2);
How to merge them to get this (with a general function):
array(
'assoc' => 'test passed',
0 => 'test index',
1 => array(
0 => array(
0 => 3,
1 => 4,
),
),
10 => array(
'test10' => array (
0 => array(
0 => 0,
1 => 1,
),
1 => array(
0 => 0,
1 => 2,
),
),
),
11 => array(
'test11' => array (
1 => 4,
2 => 5,
),
),
'multiarray' => array(
0 => array(
0 => 0,
1 => 1,
),
1 => array(
0 => 0,
0 => 2,
),
),
2 => 1,
3 => array(
0 => 2,
),
)
Preserving keys' order is not important.
[Edit] Solution:
function array_max_index_key($arr) {
$prev = -1;
if(is_array($arr)) {
$keys = array_keys($arr);
foreach($keys as $k => $key) {
if(is_numeric($key)) {
if($key == $prev+1) {
$prev=$key;
} else break;
}
}
}
return $prev;
}
function justfortesting($a1, $a2) {
$res=$a1;
$max_key=array_max_index_key($res);
if(is_array($a1)) {
foreach ($a2 as $k => $v) {
if(is_numeric($k) && $k<=$max_key) {
$max_key++;
$res[$max_key]=$v;
} elseif (is_array($v)) {
$res[$k]=justfortesting($a1[$k], $v);
} else {
$res[$k]=$v;
}
}
} else {
$res=$a2;
}
return $res;
}
$arr3=justfortesting($arr1, $arr2);
Check for is_string() instead of is_numeric()
Edited:
when you ask for
is_numeric($key)
check for
is_numeric($key) and !is_string($key)
I'm trying to sort an array by its numeric keys as if they were not numbers -- I don't want natural sorting.
$arr = [
'1000' => 'DUMMY',
'1001' => 'TEST',
'100001' => 'DUMMY1',
'100002' => 'DUMMY3',
'100004' => 'DUMMY4',
'100100' => 'test1',
'100102' => 'DUMMY123'
];
After sorting, the result should be:
[
'1000' => 'DUMMY',
'100001' => 'DUMMY1',
'100002' => 'DUMMY3',
'100004' => 'DUMMY4',
'1001' => 'TEST',
'100100' => 'test1',
'100102' => 'DUMMY123'
]
Because your array keys are "big-endian", you can explicitly sort the keys as strings (overriding the default behavior of `sort() to sort numeric values numerically). (Demo)
ksort($arr, SORT_STRING);
I'm not really sure understand what you want. But i guess it's something like that:
this sort the array
1st : by the first 4 digits of the key
2nd : by the last 2 digits if they're present
$arr = array(
'100102' => 'DUMMY123',
'100100' => 'test1',
'1000' => 'DUMMY',
'100004' => 'DUMMY4',
'100001' => 'DUMMY1',
'100002' => 'DUMMY3',
'1001' => 'TEST',
);
function mysort($a, $b) {
preg_match('/^(\d{4})(\d\d)?$/', $a, $ma);
preg_match('/^(\d{4})(\d\d)?$/', $b, $mb);
if ($ma[1] == $mb[1]) {
if (!isset($ma[2])) $ma[2] = '';
if (!isset($mb[2])) $mb[2] = '';
return strcmp($ma[2], $mb[2]);
}
return strcmp($ma[1], $mb[1]);
}
uksort($arr, 'mysort');
print_r($arr);
Output:
Array
(
[1000] => DUMMY
[100001] => DUMMY1
[100002] => DUMMY3
[100004] => DUMMY4
[1001] => TEST
[100100] => test1
[100102] => DUMMY123
)
asort() should do the trick no matter how many extra 2-character subcategories you add. With the SORT_STRING flag the category doesn't even have to be a string.
$arr =('100001'=>'DUMMY1',
'1000'=>'DUMMY',
'1001'=>'TEST',
'100002'=>'DUMMY3',
'100004'=>'DUMMY4',
'100102'=>'DUMMY123',
'100100'=>'test1');
asort($arr, SORT_STRING);
Should result in
$arr =('1000'=>'DUMMY',
'100001'=>'DUMMY1',
'100002'=>'DUMMY3',
'100004'=>'DUMMY4',
'1001'=>'TEST',
'100100'=>'test1',
'100102'=>'DUMMY123');
I have an array of items:
array(
[0] => array(
'item_no' => 1
'item_name' => 'foo
)
[1] => array(
'item_no' => 2
'item_name' => 'bar'
)
) etc. etc.
I am getting another array from a third party source and need to remove items that are not in my first array.
array(
[0] => array(
'item_no' => 1
)
[1] => array(
'item_no' => 100
) # should be removed as not in 1st array
How would I search the first array using each item in the second array like (in pseudo code):
if 'item_no' == x is in 1st array continue else remove it from 2nd array.
// Returns the item_no of an element
function get_item_no($arr) { return $arr['item_no']; }
// Arrays of the form "item_no => position in the array"
$myKeys = array_flip(array_map('get_item_no', $myArray));
$theirKeys = array_flip(array_map('get_item_no', $theirArray));
// the part of $theirKeys that has an item_no that's also in $myKeys
$validKeys = array_key_intersect($theirKeys, $myKeys);
// Array of the form "position in the array => item_no"
$validPos = array_flip($validKeys);
// The part of $theirArray that matches the positions in $validPos
$keptData = array_key_intersect($theirArray, $validPos);
// Reindex the remaining values from 0 to count() - 1
return array_values($keptData);
All of this would be easier if, instead of storing the key in the elements, you stored it as the array key (that is, you'd be using arrays of the form "item_no => item_data") :
// That's all there is to it
return array_key_intersect($theirArray, $myArray);
You can also do:
$my_array =array(
0 => array( 'item_no' => 1,'item_name' => 'foo'),
1 => array( 'item_no' => 2,'item_name' => 'bar')
);
$thrid_party_array = array(
0 => array( 'item_no' => 1),
1 => array( 'item_no' => 100),
);
$temp = array(); // create a temp array to hold just the item_no
foreach($my_array as $key => $val) {
$temp[] = $val['item_no'];
}
// now delete those entries which are not in temp array.
foreach($thrid_party_array as $key => $val) {
if(!in_array($val['item_no'],$temp)) {
unset($thrid_party_array[$key]);
}
}
Working link
If your key is not actually a key of your array but a value, you will probably need to do a linear search:
foreach ($itemsToRemove as $itemToRemove) {
foreach ($availableItems as $key => $availableItem) {
if ($itemToRemove['item_no'] === $availableItem['item_no']) {
unset($availableItems[$key]);
}
}
}
It would certainly be easier if item_no is also the key of the array items like:
$availableItems = array(
123 => array(
'item_no' => 123,
'item_name' => 'foo'
),
456 => array(
'item_no' => 456,
'item_name' => 'bar'
)
);
With this you could use a single foreach and delete the items by their keys:
foreach ($itemsToRemove as $itemToRemove) {
unset($availableItems[$itemToRemove['item_no']]);
}
You could use the following to build an mapping of item_no to your actual array keys:
$map = array();
foreach ($availableItems as $key => $availableItem) {
$map[$availableItems['item_no']] = $key;
}
Then you can use the following to use the mapping to delete the corresponding array item:
foreach ($itemsToRemove as $itemToRemove) {
unset($availableItems[$map[$itemToRemove['item_no']]]);
}