php sort multinested array - php

im having troubles with sorting array with nested array etc. Array looks like this:
$array = array(
"item" => array(
"childs" => array(
01 => array(
"name" => "Min",
"content" => "CC",
"number" => "111"
),
02 => array(
"name" => "Min",
"content" => "BB",
"number" => "101"
),
03 => array(
"name" => "Min",
"content" => "AA",
"number" => "115"
),
04 => array(
"name" => "Min",
"content" => "BB",
"number" => "100"
),
)
),
);
I want to sort that array (childs to be specific) by CONTENT and NUMBER. Here's my code:
foreach ($array as $item) {
foreach($item as $childs) {
$row = array();
$number = array();
foreach($childs as $child) {
$row[] = $child["row"];
$number[] = $child["number"];
}
array_multisort($number, SORT_ASC, SORT_NUMERIC, $row, SORT_ASC, $childs);
};
};
But it does not seem to work. I got no error but the array is not sorted. Can somebody give me a hand?

I guess root cause is: "when you loop array. Item in array is not reference variable (you have sorted in another array)".
You can try by passing reference variable.
foreach ($array as &$item) {
foreach($item as &$childs) {
$row = array();
$number = array();
foreach($childs as $child) {
$row[] = $child["row"];
$number[] = $child["number"];
}
array_multisort($number, SORT_ASC, SORT_NUMERIC, $row, SORT_ASC, $childs);
};
};

Related

How to create dynamic combination with php?

I have 3 array like
$arr = [
"color" => [["name"=>"red"]],
"size" => [["name"=>"18 inch"], ["name"=>"15 inch"]],
"type" => [["name"=>"plastic"]]
]
$combo = array();
foreach ($arr['size'] as $size) {
foreach($arr['color'] as $color){
foreach ($arr['type'] as $type) {
$variant = json_encode(['size' => $size->name, 'color' =>
$color->name, 'type' => $type->name]);
array_push($combo,$variant);
}
}
}
echo $combo;
// result
0 => "{"size":"15 inch","color":"yellow","type":"metal"}"
1 => "{"size":"18 inch","color":"yellow","type":"plastic"}"
It works properly but but there is can be less or more variants. How can I handle this.
For example
$arr = [
"size" => [["name"=>"18 inch"], ["name"=>"15 inch"]],
"type" => [["name"=>"plastic"]]
]
Or
$arr = [
"color" => [["name"=>"red"]],
"size" => [["name"=>"18 inch"], ["name"=>"15 inch"]],
"type" => [["name"=>"plastic"]],
"brand" => [['name' => 'something']],
]
For what i understand, you have to combine the arrays of properties into one array of
object.
I have to leave now, but if you need a explanation leave a comment and i updated the answers
$arr = [
"color" => [["name"=>"red"],['name'=>'yellow']],
"size" => [["name"=>"18 inch"], ["name"=>"15 inch"]],
"type" => [["name"=>"plastic"]],
"brand" => [['name' => 'something']],
];
function runFor($arr ,&$array, $keys,$index,&$positions){
foreach ($arr[$keys[$index]] as $key => $espec){
$positions[$keys[$index]] = $key;
if($index + 1 < count($keys)){
runFor($arr,$array,$keys, $index+1,$positions);
}else{
$item = (object)[];
foreach ($keys as $key){
$item->$key = $arr[$key][$positions[$key]]['name'];
}
array_push($array,$item);
}
unset($positions[$keys[$index]]);
}
}
$array = array();
$keys = array_keys($arr);
$positions = [];
runFor($arr,$array,$keys,0,$positions);
$combo = array();
foreach ($array as $item){
array_push($combo,json_encode($item));
}
var_dump($combo);

PHP - Get key value from other key

I have the following array:
$array = Array(
"0" => Array (
"id" => 1081,
"name" => "John"
),
"1" => Array (
"id" => 1082,
"name" => "Matt"
),
"2" => Array (
"id" => 1083,
"name" => "Roger"
)
);
Is there anyway I can get name if I only know the id but without having to iterate through the array?
For PHP >= 5.5.0:
$id = 1082;
$result = array_column($array, 'name', 'id')[$id];
As Barmar points out, to get an array that is easy to use with id as the index:
$id = 1082;
$result = array_column($array, 'name', 'id');
echo $result[$id];
You can make an associative array that refers to the same elements, then use that:
function make_assoc(&$array, $keyname) {
$new_array = array();
foreach ($array as &$elt) {
$new_array[$elt[$keyname]] = $elt;
}
return $new_array;
}
$assoc_array = make_assoc($array, 'id');
Now you can use $assoc_array[1083] to access the third item in the original array. And since this returns an array of references, modifying that will also modify the element of the original array.
You can use array_map to search into your array if your PHP < 5.5.0 and you don't have array_column:
<?php
$array = Array(
"0" => Array (
"id" => 1081,
"name" => "John"
),
"1" => Array (
"id" => 1082,
"name" => "Matt"
),
"2" => Array (
"id" => 1083,
"name" => "Roger"
)
);
$find = 1082;
$value = '';
$arr = array_map(function($n) use ($find, &$value) {if ($n['id'] == $find) $value = $n['name']; }, $array);
print_r($value);
?>

Put array elements with specific value to end of array

I have a multidimensional array like that:
$array = array(
1 => array(
"name" => 'Jon',
"year" => '2012'
),
2 => array(
"name" => 'Jack',
"year" => '1900'
),
3 => array(
"name" => 'Lisa',
"year" => '1900'
),
4 => array(
"name" => 'Ygritte',
"year" => '1929'
),
);
All the items that have a year of '1900' should be put to the end of the array. What is a lightweight solution?
Desired result:
$array = array(
1 => array(
"name" => 'Jon',
"year" => '2012'
),
2 => array(
"name" => 'Ygritte',
"year" => '1929'
),
3 => array(
"name" => 'Jack',
"year" => '1900'
),
4 => array(
"name" => 'Lisa',
"year" => '1900'
),
);
I assume you don't care about your indexes because you rearrange them. First thing, you should probably start indexes in your array from 0 and not for 1.
You can use the following code:
$array = array(
1 => array(
"name" => 'Jon',
"year" => '2012'
),
2 => array(
"name" => 'Jack',
"year" => '1900'
),
3 => array(
"name" => 'Lisa',
"year" => '1900'
),
4 => array(
"name" => 'Ygritte',
"year" => '1929'
),
);
$array = array_values($array);
for ($i=0, $c = count($array); $i<$c; ++$i) {
if ($array[$i]['year'] == '1900') {
$array[] = $array[$i];
unset($array[$i]);
}
}
$array = array_values($array);
foreach ($array as $k => $v) {
echo $k.' '.$v['name'].' '.$v['year']."<br />";
}
Result for this is:
0 Jon 2012
1 Ygritte 1929
2 Jack 1900
3 Lisa 1900
Of course if you want, you can change your keys adding 1 to each one (starting from the last element) so you have the same output as in question but I assume this one is enough for you.
The simplest approach could be something like this:
Find the element that has year 1900 (iterating the loop) then,
For example working for index 3
$tmp = $myArray['3'];
unset($myArray['3'];
$myArray['3'] = $tmp;
$tmp is a temporary variable inside the loop.
Try using SplHeap
class MyQueue extends SplHeap
{
public function compare($item1, $item2)
{
if ($item1['year'] === $item2['year']) return 0;
return ($item1['year'] == 1900) ? -1 : 0;
}
}
$queue = new MyQueue();
foreach ($array as $item) {
$queue->insert($item);
}
$queue->top();
$array = array();
while($queue->valid()){
$array[] = $queue->current();
$queue->next();
}
print_r($array);
Hope this following code will help you:
function aasort (&$array, $key) {
$sorter=array();
$ret=array();
reset($array);
foreach ($array as $ii => $va) {
$sorter[$ii]=$va[$key];
}
rsort($sorter);
foreach ($sorter as $ii => $va) {
$ret[$ii]=$array[$ii];
}
$array=$ret;
}
aasort($array,"year");
print_r($array);

Not getting array all values using php

I have this following array
$question = array(
"ques_15" => array(
"name" => array(
"0" => "aaa"
)
),
"ques_16" => array(
"name" => array(
"0" => "bbb",
"1" => "ccc"
)
)
);
$i=0;
foreach($question as $k=>$v)
{
echo $question[$k]['name'][$i];
$i++;
}
But my output is only
aaaccc
I am missing the value bbb
You need to iterate the inner 'name' arrays - you could use a nested foreach loop:
$question = array(
"ques_15" => array(
"name" => array(
"0" => "aaa"
)
),
"ques_16" => array(
"name" => array(
"0" => "bbb",
"1" => "ccc"
)
)
);
foreach($question as $quest)
{
foreach($quest['name'] as $val)
{
echo $val;
}
}
you should loop though like so
foreach($question as $q)
{
foreach($q['name'] as $v)
{
echo $v;
}
}
in foreach you don't need a counter $i, it's for while() or for()
you array is two dimensional so you need 2 foreach
Check it out in a functional way.
The shorthand array declaration works only on PHP 5.4+ though, but it still works with your longhand array declaration.
$questions = [
'ques_15' => ['name' => ['aaa']],
'ques_16' => ['name' => ['bbb', 'ccc']]
];
array_map(function($a){
foreach ($a['name'] as $v) echo $v;
}, $questions);

Run throw array of associative array and find keys

I have two arrays that look like this:
(this one is ordered by value_max)
$max_values = [
["name" => "john", "id" => 5, "value_max" => 500],
["name" => "john", "id" => 3, "value_max" => 200],
...
];
$min_values = [
["name" => "john", "id" => 5, "value_min" => 100],
["name" => "john", "id" => 3, "value_min" => 150],
...
];
And I need to have a final array like this:
(This one stills need to be ordered by value_max, so I assume I could just overwrite the first array with the calculations done with the second)
$max_and_difference_values = [
["name" => "john", "id" => 5, "value_max" => 500, "difference_value" => 400],
["name" => "john", "id" => 3, "value_max" => 200, "difference_value" => 50 ],
...
];
My question is pretty straight: What is the best/effective way to run through both first arrays and build the last one. Assuming that the size of the arrays can be of around 150 elements.
To avoid looping through all arrays repeatedly, index one array by the field you want to merge on, i.e. the 'id' key:
$second = array_combine(array_map(function ($i) { return $i['id']; }, $second_array), $second_array);
Then looping through the other and comparing the values is pretty easy:
$third = array();
foreach ($first_array as $i) {
$third[] = $i + array('difference_value' => $i['value_max'] - $second[$i['id']]['value_min']);
}
If it's guaranteed that both arrays will have exactly matching keys, you don't even need the first step and just go by already existing keys.
This will sort your array. So you can sort the second array.
<?php
$min_values = array(
array("name" => "john", "id" => 5, "value_min" => 100),
array("name" => "john", "id" => 3, "value_min" => 150),
);
function aasort (&$array, $key) {
$sorter=array();
$ret=array();
reset($array);
foreach ($array as $ii => $va) {
$sorter[$ii]=$va[$key];
}
asort($sorter);
foreach ($sorter as $ii => $va) {
$ret[$ii]=$array[$ii];
}
$array=$ret;
}
aasort($min_values,"id");
echo "<pre>";
print_r($min_values);
echo "</pre>";
?>
And then you can use the logic what Alessandro Minoccheri mentioned.
$arr = array();
for ($i=0; $i<count($first_array);$i++){
$arr['name'] = $first_array[$i]['name'];
$arr['id'] = $first_array[$i]['id'];
$arr['value_max'] = $first_array[$i]['value_max'];
$arr['difference_value'] = $first_array[$i]['value_max']-$second[$i['id']]['value_max'] ;
}
As you have not shared how the second array with the minimum values is ordered (in itself and relative to the maximum values array), I'd say, index the minimum values by the id entry and then do the calculation in a second iteration. It should be fast enough, 150 elements is just "nothing":
$max_values = [
["name" => "john", "id" => 5, "value_max" => 500],
["name" => "john", "id" => 3, "value_max" => 200],
];
$min_values = [
["name" => "john", "id" => 5, "value_min" => 100],
["name" => "john", "id" => 3, "value_min" => 150],
];
$min_values_by_id = [];
foreach($min_values as $min) {
$min_values_by_id[$min['id']] = $min['value_min'];
}
$max_and_difference_values = $max_values;
foreach($max_and_difference_values as &$entry)
{
$entry['difference_value'] = $entry['value_max'] - $min_values_by_id[$entry['id']];
}
unset($entry);
print_r($max_and_difference_values);
This is just a straight forward example, nothing fancy. Demo
the following works for me. I'm not a PHP expert though, i.e. I'm not so familiar with cloning (note the empty clone array). Note that it only copies existing properties (if one array does contain a min_value and another does only contain a some other key)
In essence
function convertArr( $arr ) {
// Easy referencing without having to search through the arrays more than once for a matching id
$new_arr = array();
foreach( $arr as $array ) {
$new_arr[ $array['id'] ] = cloneArr( $array );
}
return $new_arr;
}
function merge( $arr1, $arr2 ) {
$convertedArr1 = convertArr( $arr1 );
$convertedArr2 = convertArr( $arr2 );
$arr = array();
// Based on the ordered array
foreach( $convertedArr1 as $array ) {
$id = $array['id'];
$tempArr = array();
foreach( $convertedArr1[ $id ] as $k => $v ) {
$tempArr[ $k ] = $v;
}
foreach( $convertedArr2[ $id ] as $k => $v ) {
$tempArr[ $k ] = $v;
}
array_push( $arr, $tempArr );
}
return $arr;
}
Full example:
<?php
//$arr1 = [ ["name" => "john", "id" => 5, "value_max" => 500], ["name" => "john", "id" => 3, "value_max" => 200] ];
//$arr2 = [ ["name" => "john", "id" => 5, "value_min" => 100], ["name" => "john", "id" => 3, "value_min" => 150] ];
$arr1 = array(
array( "name" => "john", "id" => 5, "value_max" => 500 ),
array( "name" => "john", "id" => 3, "value_max" => 200 )
);
$arr2 = array(
array( "name" => "john", "id" => 5, "value_min" => 100 ),
array( "name" => "john", "id" => 3, "value_min" => 150 )
);
function neatPrint( $arr ) {
echo "<pre>";
print_r( $arr );
echo "</pre>";
}
echo "<h2>Before</h2>";
neatPrint( $arr1 );
neatPrint( $arr2 );
echo "<hr/>";
function cloneArr( $old ) {
// I dunno how to properly clone
return $old;
}
function convertArr( $arr ) {
// Easy referencing without having to search through the arrays more than once for a matching id
$new_arr = array();
foreach( $arr as $array ) {
$new_arr[ $array['id'] ] = cloneArr( $array );
}
return $new_arr;
}
function merge( $arr1, $arr2 ) {
$convertedArr1 = convertArr( $arr1 );
$convertedArr2 = convertArr( $arr2 );
$arr = array();
// Based on the ordered array
foreach( $convertedArr1 as $array ) {
$id = $array['id'];
$tempArr = array();
neatPrint( $convertedArr1[ $id ] );
neatPrint( $convertedArr2[ $id ] );
foreach( $convertedArr1[ $id ] as $k => $v ) {
$tempArr[ $k ] = $v;
}
foreach( $convertedArr2[ $id ] as $k => $v ) {
$tempArr[ $k ] = $v;
}
array_push( $arr, $tempArr );
}
echo "<h2>Result</h2>";
return $arr;
}
echo "<h2>Loopthrough</h2>";
neatPrint( merge( $arr1, $arr2 ) );
?>
Let me know what you think :-)
if the element are in order try this code:
$arr = array();
for ($i=0; $i<count($first_array);$i++){
$arr['name'] = $first_array[$i]['name'];
$arr['id'] = $first_array[$i]['id'];
$arr['value_max'] = $first_array[$i]['value_max'];
$arr['difference_value'] = $first_array[$i]['value_max']-$second[$i['id']]['value_max'] ;
}

Categories