reorder multi-dimensional array in PHP - php

I have a multi-dimensional array that I need to reorder.
I need to sort the array so that the first thing that will take into account the LEVEL, then SECTION, where SECTION is equal to the ID of the previous element.
Can someone help me?
Thanks.
Here is the array:
Array
(
[0] => Array
(
[LEVEL] => 1
[ID] => 1_1
[SECTION] => _
)
[1] => Array
(
[LEVEL] => 1
[ID] => 1_2
[SECTION] => _
)
[2] => Array
(
[LEVEL] => 2
[ID] => 2_1
[SECTION] => 1_1
)
[3] => Array
(
[LEVEL] => 2
[ID] => 2_2
[SECTION] => 1_2
)
[4] => Array
(
[LEVEL] => 3
[ID] => 3_1
[SECTION] => 2_1
)
[5] => Array
(
[LEVEL] => 3
[ID] => 3_2
[SECTION] => 2_2
)
and here is the result I need:
Array
(
[0] => Array
(
[LEVEL] => 1
[ID] => 1_1
[SECTION] => _
)
[2] => Array
(
[LEVEL] => 2
[ID] => 2_1
[SECTION] => 1_1
)
[4] => Array
(
[LEVEL] => 3
[ID] => 3_1
[SECTION] => 2_1
)
[1] => Array
(
[LEVEL] => 1
[ID] => 1_2
[SECTION] => _
)
[3] => Array
(
[LEVEL] => 2
[ID] => 2_2
[SECTION] => 1_2
)
[5] => Array
(
[LEVEL] => 3
[ID] => 3_2
[SECTION] => 2_2
)

Correct me if I'm wrong, but it looks like all the information you need for sorting is in the ID. Groups are contained in the number following the underscore, and levels in the number preceding it. Therefore, the order can be determined by reversing the order of these numbers and performing a natural order string comparison:
1_1, 2_1, 3_1, 4_1, 1_2, 2_2, 3_2, 1_3, 2_3, 3_3, 4_3, etc.
Becomes:
1-1, 1-2, 1-3, 1-4, 2-1, 2-2, 2-3, 3-1, 3-2, 3-3, 3-4, etc.
Therefore, if your initial array is called $arr:
$ord = array_map(function($a) {return $a['ID'];}, $arr);
$ord = preg_replace('/(\d+)_(\d+)/', '$2-$1', $ord);
array_multisort($ord, SORT_NATURAL, $arr);
If you're using PHP 5.5:
$ord = preg_replace('/(\d+)_(\d+)/', '$2-$1', array_column($arr, 'ID'));
array_multisort($ord, SORT_NATURAL, $arr);

It was interesting to work on your question, Please check my below solution on your query,
It's working fine for me:
$arrData=array(
array(
'LEVEL'=>1,
'ID'=>'1_1',
'SECTION'=>''
),
array(
'LEVEL'=>'3',
'ID'=>'3_1',
'SECTION'=>''
),
array(
'LEVEL'=>'3',
'ID'=>'3_2',
'SECTION'=>''
),
array(
'LEVEL'=>2,
'ID'=>'2_1',
'SECTION'=>''
),
array(
'LEVEL'=>1,
'ID'=>'1_2',
'SECTION'=>''
),
);
$arrLevels=array();
foreach($arrData as $key=>$val)
{
if(!in_array($val['LEVEL'], $arrLevels))
{
$arrLevels[]=$val['LEVEL'];
}
}
sort($arrLevels);
$arrDataNew=array();
$arrSortIndexes=array();
do
{
foreach ($arrLevels as $level)
{
//array_walk($arrData, 'sort_data',$level,$arrSortIndexes,$arrData);
$arrCurrentLevel=array();
foreach($arrData as $key=>$dataC)
{
if($dataC['LEVEL']==$level)
{
$arrCurrentLevel[intval(end(explode('_',$dataC['ID'])))]=$key;
}
}
if(sizeof($arrCurrentLevel)>0)
{
$keyOfArrData=$arrCurrentLevel[min(array_keys($arrCurrentLevel))];
$arrDataNew[]=$arrData[$keyOfArrData];
unset($arrData[$keyOfArrData]);
}
}
}while(sizeof($arrData)>0);
print_r($arrDataNew);

I finally solved this way, it is not the fastest solution, but it works at least as need
$i=0;
foreach ($polozky as $id => $polozka)
{
if ($polozka["LEVEL"] == 1)
{
$i++;
}
}
$j=0;
foreach ($polozky as $id => $polozka)
{
if ($polozka["LEVEL"] == 2)
{
$j++;
}
}
$k=0;
foreach ($polozky as $id => $polozka)
{
if ($polozka["LEVEL"] == 3)
{
$k++;
}
}
$stack = array();
for($l = 0; $l < $i; ++$l)
{
array_push($stack, $polozky[$l]);
$id1 = $polozky[$l]["ID"];
for($m = 0; $m < $j+$i; ++$m)
{
if($polozky[$m]["SECTION"] == $id1)
{
array_push($stack, $polozky[$m]);
$id2 = $polozky[$m]["ID"];
for($n = 0; $n < $k+$j+$i; ++$n)
{
if($polozky[$n]["SECTION"] == $id2)
{
array_push($stack, $polozky[$n]);
}
}
}
}
}

Related

Sort all child by parent id

i have array like this:
(
[0] => Array
(
[id] => 1
[name] => Bazowa
[parent_id] => 0
)
[1] => Array
(
[id] => 2
[name] => Główna
[parent_id] => 1
)
[2] => Array
(
[id] => 12
[name] => PlayStation
[parent_id] => 2
)
[3] => Array
(
[id] => 13
[name] => Xbox
[parent_id] => 2
)
[4] => Array
(
[id] => 14
[name] => Nintendo
[parent_id] => 2
)
[5] => Array
(
[id] => 15
[name] => PC
[parent_id] => 2
)
)
and i want sort this array like tree on screenshot below:
Screen of tree what I want
i trying use this Sort array values based on parent/child relationship
foreach($xml->children()->children() as $value) {
if($value->active == 1) {
$categories[] = [
'id' => (int) $value->id,
'name' => (string) $value->name->language,
'parent_id' => (int) $value->id_parent
];
}
}
$parent_ids = [];
$parents = ['' => []];
foreach($categories as $val) {
$parents[$val['parent_id']][] = $val;
}
$sorted = $parents[''];
dump($parents); exit;
for($val = reset($sorted); $val; $val = next($sorted)) {
if(isset($parents[$val[0]])) {
foreach($parents[$val[0]] as $next) {
$sorted[] = $next;
}
}
}
The most important thing for me is that everything displays well in select, which is something like this:
-Playstation
-- Playstation 5
--- Gry
--Playstation 3
--- Gry
Anyone can help me?
EDIT:
Problem solved by Build a tree from a flat array in PHP
This should work
usort($arr, function($a, $b) {
return $a["parent_id"] > $b["parent_id"];
});

Remove duplicates array

I have an array looks like this,
Array
(
[0] => Array
(
[id] => 224983
[name] => James
[weight] => 0
[bank] => Bank A
[transaction] => 1
[total] => 7682000000
[reference] => Edward
[type] => BRANCH
[reference_id] => 222818
[account_number] => 1220007355285
)
[1] => Array
(
[id] => 224984
[name] => James
[weight] => 0
[bank] => Bank A
[transaction] => 1
[total] => 7682000000
[reference] => Edward
[type] => BRANCH
[reference_id] => 222819
[account_number] => 1220007355285
)
[3] => Array
(
[id] => 224985
[name] => Maria
[weight] => 0
[bank] => Bank B
[transaction] => 1
[total] => 1500000000
[reference] => Andrey
[type] => BRANCH
[reference_id] => 247620
[account_number] => 1220000412901
)
)
When the account_number, reference, and name is same I want to remove the other one, and keep the last based on id...
Please someone help me to find out, I've been stuck here, so the output would be remove array[0] with ['id] => 224983, and the rest array would be the result
If you specifically just want to compare only three field of array than you can try below way. Which checks of duplicate and unset previous entries. Here $data is array input
foreach ($data as $key => $row) {
$id = $row['id'];
$name = $row['name'];
$reference = $row['reference'];
$flag = 0;
for($i = $key + 1; $i < count($data); $i++)
{
if(($data[$i]['id'] == $id) && ($data[$i]['name'] == $name) && ($data[$i]['reference'] == $reference))
{
if($key != $i)
unset($data[$key]);
}
}
}
Result would be
Array
(
[1] => Array
(
[id] => 224983
[name] => James
[weight] => 0
[bank] => Bank A
[transaction] => 1
[total] => 7682000000
[reference] => Edward
[type] => BRANCH
[reference_id] => 222818
[account_number] => 1220007355285
)
[2] => Array
(
[id] => 224985
[name] => Maria
[weight] => 0
[bank] => Bank B
[transaction] => 1
[total] => 1500000000
[reference] => Andrey
[type] => BRANCH
[reference_id] => 247620
[account_number] => 1220000412901
)
)
Try the following function, This will help to remove duplicates arrays.
function array_unique_multidimensional($input)
{
$serialized = array_map('serialize', $input);
$unique = array_unique($serialized);
return array_intersect_key($input, $unique);
}
It seems inelegant, but I think you would need to loop through your previous array elements to check IDs. You could create a function something like this:
function id_exists_prior(&$my_array, $array_index) {
for($i = 0; $i < $array_index; $i++) {
if($my_array[$i]['id'] === $my_array[$array_index]['id']) return false;
}
return true;
}
Then you can call it on any array element you wish, or loop through the whole array to check for duplicates. An example of the latter:
$your_array = [/*Your array data*/];
for($key = 0; $key < count($your_array); $key++) {
if(id_exists_prior($your_array, $key)) //Do your thing
}
The reason for passing the array key into the function is so that the function ONLY checks for prior duplicates.
Hope this helps!

Find all possible permutations without repeating the value

Let's say I have this set of arrays as input:
[
0 => [1,2,4,5],
1 => [2,3,4],
2 => [1,3],
]
I would like to find all permutations possible selecting one value from each array. That value would be unique in the final result, so it won't repeat. For example, I can't have 1 twice in the result.
The count of arrays on input is the same as count of arrays on output.
Examples of combinations wanted (key=>value):
[0 => 1,1 => 2,2 => 3]
[0 => 2,1 => 3,2 => 1]
[0 => 5,1 => 2,2 => 1]
[0 => 1,1 => 3,2 => null]
Wrong results
[0 => 1,1 => 2,2 => 1]
or
[0 => 2,1 => 2,2 => 3]
I would like to get set of all possible permutations using PHP. How can I do that?
I have attached real data set http://pastebin.com/U6Hyawm4 However, I have no idea how many permutations there may be.
Here's a non-recursive version that's also optimized
/**
* Generates all the possible unique N-tuples from an array of N arrays of integers
*
* #param array $input
* #return array
*/
function generateCombinations(array &$input) {
// since the example results included [1, 3, null] I have assumed that
// null is a possible value of each set.
$sets = [];
foreach($input as $set) {
if(!in_array(null, $set)) {
$set[] = null;
}
$sets[] = $set;
}
// by working on the iterators of each array this loop
// linearizes the entire set of possible combinations
// and iterates it (skipping as many as it can).
$output = [];
$setCount = count($sets);
while(current($sets[0]) !== false) {
$testCombo = [];
for($setIdx = 0; $setIdx < $setCount; $setIdx++) {
if(!in_array(current($sets[$setIdx]), $testCombo)) {
$testCombo[] = current($sets[$setIdx]);
}
else {
// when a combination is thrown out as duplicate
// iterate to skip any other combo's that would also
// contain that duplicate
iterateSets($sets, $setIdx);
break;
}
}
// if there were no duplicates add it to the output and iterate
if(count($testCombo) == $setCount) {
$output[] = $testCombo;
iterateSets($sets, $setCount - 1);
}
}
return $output;
}
/**
* Iterates to the next potentially valid combination. I think of
* this like doing long-hand addition. Add 1 and carry is akin to
* next and reset.
*
* #param array $sets
* #param $index
*/
function iterateSets(array &$sets, $index) {
// reset iterators of all sets past the current one to skip
// combos that cannot be valid
for($i = $index + 1, $ic = count($sets); $i < $ic; $i++) {
reset($sets[$i]);
}
// always move one on current set
next($sets[$index]);
while($index > 0 && current($sets[$index]) === false) {
// wrap if current set is at the end
reset($sets[$index]);
$index--;
// move one for the preceding set
next($sets[$index]);
// then repeat
}
}
The resulting array is:
[
[1,2,3]
[1,2,null]
[1,3,null]
[1,4,3]
[1,4,null]
[1,null,3]
[2,3,1]
[2,3,null]
[2,4,1]
[2,4,3]
[2,4,null]
[2,null,1]
[2,null,3]
[4,2,1]
[4,2,3]
[4,2,null]
[4,3,1]
[4,3,null]
[4,null,1]
[4,null,3]
[5,2,1]
[5,2,3]
[5,2,null]
[5,3,1]
[5,3,null]
[5,4,1]
[5,4,3]
[5,4,null]
[5,null,1]
[5,null,3]
[null,2,1]
[null,2,3]
[null,3,1]
[null,4,1]
[null,4,3]
]
Here's an inefficient version:
$input = array(
[1,2,4,5],
[2,3,4],
[1,3]
);
function appendUnique($subs, $i) {
global $input;
if ($i == count($input)) {
return $subs;
}
$output = array();
foreach ($subs as $sub) {
foreach ($input[$i] as $v) {
$new_sub = array_values($sub);
if (in_array($v, $sub)) {
$new_sub[] = null;
} else {
$new_sub[] = $v;
}
$output[] = $new_sub;
}
}
return appendUnique($output, $i+1);
}
$output = appendUnique([[]], 0);
$output_json = array();
foreach ($output as $row) {
$output_json[] = json_encode($row);
}
$output_json = array_unique($output_json);
$deduped = array();
foreach ($output_json as $json) {
$deduped[] = json_decode($json);
}
print_r($deduped);
outputs:
Array
(
[0] => Array
(
[0] => 1
[1] => 2
[2] =>
)
[1] => Array
(
[0] => 1
[1] => 2
[2] => 3
)
[2] => Array
(
[0] => 1
[1] => 3
[2] =>
)
[3] => Array
(
[0] => 1
[1] => 4
[2] =>
)
[4] => Array
(
[0] => 1
[1] => 4
[2] => 3
)
[5] => Array
(
[0] => 2
[1] =>
[2] => 1
)
[6] => Array
(
[0] => 2
[1] =>
[2] => 3
)
[7] => Array
(
[0] => 2
[1] => 3
[2] => 1
)
[8] => Array
(
[0] => 2
[1] => 3
[2] =>
)
[9] => Array
(
[0] => 2
[1] => 4
[2] => 1
)
[10] => Array
(
[0] => 2
[1] => 4
[2] => 3
)
[11] => Array
(
[0] => 4
[1] => 2
[2] => 1
)
[12] => Array
(
[0] => 4
[1] => 2
[2] => 3
)
[13] => Array
(
[0] => 4
[1] => 3
[2] => 1
)
[14] => Array
(
[0] => 4
[1] => 3
[2] =>
)
[15] => Array
(
[0] => 4
[1] =>
[2] => 1
)
[16] => Array
(
[0] => 4
[1] =>
[2] => 3
)
[17] => Array
(
[0] => 5
[1] => 2
[2] => 1
)
[18] => Array
(
[0] => 5
[1] => 2
[2] => 3
)
[19] => Array
(
[0] => 5
[1] => 3
[2] => 1
)
[20] => Array
(
[0] => 5
[1] => 3
[2] =>
)
[21] => Array
(
[0] => 5
[1] => 4
[2] => 1
)
[22] => Array
(
[0] => 5
[1] => 4
[2] => 3
)
)

Php array iteration

I have following array :
[1] => Array
(
[entity_id] => 5877
[parent_id] => 5862
[label] => Railbikes
[name] => railbikes
[icon] => books.svg
[level] => 5
[tab_id] => 353
)
[2] => Array
(
[entity_id] => 5756
[parent_id] => 5754
[label] => Tournaments
[name] => tournaments
[icon] => books.svg
[level] => 5
[tab_id] => 354
)
[3] => Array
(
[entity_id] => 5756
[parent_id] => 5754
[label] => Tournaments
[name] => tournaments
[icon] => books.svg
[level] => 5
[tab_id] => 357
)
In this array label => Tournaments repeats twice and this is the case for whole array many labels are repeating twice , thrice and many time .
I want this array to be shown like that there will be a unique label and there is tab_id in each array which is different . This tab_id sholdd be appended to the unique label .
The final array should look like this .
[1] => Array
(
[entity_id] => 5877
[parent_id] => 5862
[label] => Railbikes
[name] => railbikes
[icon] => books.svg
[level] => 5
[tab_id] => 353
)
[2] => Array
(
[entity_id] => 5756
[parent_id] => 5754
[label] => Tournaments
[name] => tournaments
[icon] => books.svg
[level] => 5
[tab_id] => 354 , 357
)
Thanks.
$arr = array(1 => array
(
entity_id => 5877,
parent_id => 5862,
label => Railbikes,
name => railbikes,
icon => books.svg,
level => 5,
tab_id => 353
),
2 => array
(
entity_id => 5756,
parent_id => 5754,
label => Tournaments,
name => tournaments,
icon => books.svg,
level => 5,
tab_id => 354
),
3 => array
(
entity_id => 5756,
parent_id => 5754,
label => Tournaments,
name => tournaments,
icon => books.svg,
level => 5,
tab_id => 357
)
);
print("<pre>");
foreach ($arr AS $key => $value){
/*foreach ($value AS $innerKey => $innerValue){
}*/
if($arr[$key]['label'] == $arr[$key-1]['label'] )
{
$newArr[$key-1]['tab_id'] = $arr[$key]['tab_id'].",". $arr[$key-1]['tab_id'];
}
else{
$newArr[$key]= $arr[$key];
}
}
print_r($newArr);
Try this out
$new_array = array();
$items = array();
foreach( $array as $item )
{
$check = array_search( $item['entity_id'], $items, true );
if ( $check === false )
{
$temp = $item;
$temp['tab_id'] = array( $item['tab_id'] );
$new_array[] = $temp;
$items[] = $temp['entity_id'];
}
else
{
$new_array[$check]['tab_id'][] = $item['tab_id'];
}
}
where $array is your original array the you showed us. You can replace it at the end with $array = $new_array; if you want to keep the same name in the rest of the code.
Also, keep in mind that tab_id is now an array to fit with your requirement.
If you really want to keep it as in your example, you could use
$new_array = array();
$items = array();
foreach( $array as $item )
{
$check = array_search( $item['entity_id'], $items, true );
if ( $check === false )
{
$new_array[] = $item;
$items[] = $item['entity_id'];
}
else
{
$new_array[$check]['tab_id'] .= ', '.$item['tab_id'];
}
}
If the entity_id is always the same then you can 'cheat' a bit:
$new_array = array();
foreach($array as $item)
{
if(!isset($new_array[$item['entity_id']]) $new_array[$item['entity_id']] = $item;
}
$new_array = array_values($new_array);
PS: Always try to prevent double data, doesn't make your script faster ;)

PHP combine array based on value of particular element

I have an array that looks like this
Array (
[0] => Array
(
[id] => 123
[count] => 1
)
[1] => Array
(
[id] => 123
[count] => 3
)
[2] => Array
(
[id] => 513
[count] => 0
)
[3] => Array
(
[id] => 561
[count] => 1
)
[4] => Array
(
[id] => 613
[count] => 7
)
)
What I want to do is create a new array, that totals the count where the id values are the same. So for example, the new array would look like this:
Array (
[0] => Array
(
[id] => 123
[count] => 4
)
[1] => Array
(
[id] => 513
[count] => 0
)
[2] => Array
(
[id] => 561
[count] => 1
)
[3] => Array
(
[id] => 613
[count] => 7
)
)
Would anyone know a good method to do this?
Thank you!
Short and simple:
$new_array = array();
foreach($data_array as $value) {
if(array_key_exists($value['id'], $new_array)) {
$new_array[$value['id']] += $value['count'];
} else {
$new_array[$value['id']] = $value['count'];
}
}
echo print_r($new_array,true);
I made it id => value since there didn't seem to need another array for data when the id could be used as the array's key.
Any reason why you are not making an associative array of id => count
You can do it with the following function (I didn't tested the code, but it should work ):
function get_count_array($arr) {
$new_array = array();
foreach($arr as $item) {
$found = false;
//loop through all the current new items to check if we already have it
for($i = 0; $i < count($new_array); $i++) {
//do we have it?
if($new_array[$i]['id'] == $item['id']) {
$new_array[$i]['count'] += 1;
$found = true;
break;
}
}
if(!$found) {
$new_array[] = array('id' => $item['id'], 'count' => 0);
}
}
return $new_array;
}

Categories