Php array iteration - php

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

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

Combine Arrays into One Multidimensional Array using PHP

I am trying to combine arrays into one single multidimensional array. There could be more than 5 arrays that needs to be combined so I need a code that will automatically combine all arrays no matter how many they are. I tried array_merge but it requires manual defining of arrays in comma formatted parameters.
The code to convert is:
Array
(
[id] => 1
[name] => Item 1
[slug] => item-slug-1
[parent] => 0
)
Array
(
[id] => 2
[name] => Item 2
[slug] => item-slug-2
[parent] => 1
)
Array
(
[id] => 3
[name] => Item 3
[slug] => item-slug-3
[parent] => 2
)
Array
(
[id] => 4
[name] => Item 4
[slug] => item-slug-4
[parent] => 3
)
Array
(
[id] => 5
[name] => Item 5
[slug] => item-slug-5
[parent] => 3
)
And this is how I would like it to look:
Array
(
[0] => Array
{
[id] => 1
[name] => Item 1
[slug] => item-slug-1
[parent] => 0
}
[1] => Array
{
[id] => 2
[name] => Item 2
[slug] => item-slug-2
[parent] => 1
}
[2] => Array
{
[id] => 3
[name] => Item 3
[slug] => item-slug-3
[parent] => 2
}
[3] => Array
{
[id] => 4
[name] => Item 4
[slug] => item-slug-4
[parent] => 3
}
[4] => Array
{
[id] => 5
[name] => Item 5
[slug] => item-slug-5
[parent] => 3
}
)
Here is how the arrays are generated:
I receive a response JSON from the server that looks like this:
[{"slug":"item-slug-1","name":"Item 1","id":1},{"slug":"item-slug-2","name":"Item 2","id":2},{"slug":"item-slug-3","name":"Item 3","id":3,"children":[{"slug":"item-slug-4","name":"Item 4","id":4},{slug":"item-slug-5","name":"Item 5","id":5}]}]
I decode the JSON then convert it to an array like this:
$categories_obj = json_decode( $_POST['order'] );
$categories_arr = json_decode(json_encode( $categories_obj ), true);
I created a function that walks through each item so it would be easier to insert into my database:
function walk_and_update($data, $parent = 0, $count = 0) {
if( is_array($data) ) {
$combine = array();
/* The arrays are generated here */
foreach( $data as $key => $row ) {
$formatted = array(
'id' => $row['id'],
'name' => $row['name'],
'slug' => $row['slug'],
'parent' => $parent
);
print_r( $formatted );
/* My SQL update is here */
if( isset( $row['children'] ) ) {
walk_and_update( $row['children'], $row['id'], $count );
}
}
}
}
Then I use the function like this:
walk_and_update( $categories_arr );
Like this:
$arr1 = Array(
'id' => 1,
'name' => 'Item 1',
'slug' => 'item-slug-1',
'parent' => 0);
$arr2 = Array(
'id' => 2,
'name' => 'Item 2',
'slug' => 'item-slug-2',
'parent' => 1);
$arr3 = Array(
'id' => 3,
'name' => 'Item 3',
'slug' => 'item-slug-3',
'parent' => 2);
$new_arr = array();
for($i=1;$i<=3;$i++) {
$var_name = 'arr'.$i;
array_push($new_arr,$$var_name);
}
echo "<pre>";print_r($new_arr);
Output:
Array
(
[0] => Array
(
[id] => 1
[name] => Item 1
[slug] => item-slug-1
[parent] => 0
)
[1] => Array
(
[id] => 2
[name] => Item 2
[slug] => item-slug-2
[parent] => 1
)
[2] => Array
(
[id] => 3
[name] => Item 3
[slug] => item-slug-3
[parent] => 2
)
)
you could make function to handle the array, then return expected array to multidimensional array.
can i know first, that the array you want to merging , did they produce one by one or just one time that can produce many array ?
//you could do this if your array produces one time only
$counter = 0;
$new_array=array();
foreach (your array as $key => $val)
{
$new_array[$counter]['id']= $val['id'];
$new_array[$counter]['name']= $val['name'];
$new_array[$counter]['slug']= $val['slug'];
$new_array[$counter]['parent'] = $val['parent'];
$counter++;
}
//if your array produces more than one time
function main ()
{
$data['counter']=0;
$data['newarray']=array();
$data = $this->mergin_array(your array,$data['counter'])
}
function merging_array(your array,$counter)
{
$data = array();
$counter_new = $counter;
foreach(your array as $key => $val)
{
$data['newarray'][$counter]['id'] = $val['id'];
$data['newarray'][$counter]['name'] = $val['name'];
$data['newarray'][$counter]['slug'] = $val['slug'];
$data['newarray'][$counter]['parent'] = $val['parent'];
$counter_new++;
}
$data['counter'] = $counter_new;
return $data;
}
so no matter how many you use , when you access the $data['newarray'] in your main function it will get you the combined for many array

PHP - merging 2D array by keys

How can I merge these array together?
Array
(
[0] => Array
(
[type] => Person
[relevance] => 0.700000
[count] => 300
[text] => Chris
)
)
Array
(
[0] => Array
(
[type] => Person
[relevance] => 0.900000
[count] => 400
[text] => Chris
)
[1] => Array
(
[type] => Person
[relevance] => 0.500000
[count] => 200
[text] => Tom
)
)
or array like this:
Array
(
[0] => Array
(
[type] => Person
[relevance] => 0.700000
[count] => 300
[text] => Chris
)
[1] => Array
(
[type] => Person
[relevance] => 0.900000
[count] => 400
[text] => Chris
)
[2] => Array
(
[type] => Person
[relevance] => 0.500000
[count] => 200
[text] => Tom
)
)
The expected result is:
Array
(
[0] => Array
(
[type] => Person
[relevance] => 0.800000
[count] => 700
[text] => Chris
)
[1] => Array
(
[type] => Person
[relevance] => 0.500000
[count] => 200
[text] => Tom
)
)
[relevance] value is an average number
[count] value is an incremental number
The merging of these array should base on [text] value.
How can I do this with php in a fast way?
Thanks for helping.
If this is the array
$array = Array(
Array(
'type' => 'Person',
'relevance' => .7,
'count' => 300,
'text' => 'Chris'
),
Array(
'type' => 'Person',
'relevance' => .9,
'count' => 400,
'text' => 'Chris'
),
Array(
'type' => 'Person',
'relevance' => .5,
'count' => 200,
'text' => 'Tom'
),
);
then:
$tmp = Array();
foreach($array as $obj) {
if(!isset($tmp[$obj['text']])) {
$tmp[$obj['text']] = array_merge(Array('total_count'=>1),$obj);
continue;
}
$tmp[$obj['text']]['count'] += $obj['count'];
$tmp[$obj['text']]['relevance'] += $obj['relevance'];
$tmp[$obj['text']]['total_count']++; // useful for average calculation
}
$result = Array();
foreach($tmp as $key=>$obj) {
$obj['relevance'] = $obj['relevance']/$obj['total_count'];
unset($obj['total_count']); // useless now
$result[] = $obj;
}
print_r($result);
Something like this maybe:
$newArray = array();
foreach ($oldArray as $item) {
if (!array_key_exists($item['text'], $newArray)) {
$newArray[$item['text']] = $item;
$newArray[$item['relevance_values']] = array();
} else {
$newArray[$item['text']]['count'] += $item['count'];
$newArray[$item['relevance_values']][] = $item['relevance'];
}
}
foreach ($newArray as $item) {
$relevance = 0;
foreach ($item['relevance_values'] as $value) {
$relevance += $value;
}
$item['relevance'] = $relevance / count($item['relevance_values']);
}
Try this:
function mergeOnText($array){
$results = array();
foreach($array as $person){
$found = -1;
foreach($results as $i => $res)
if($res['text'] == $person['text']){
$found = $i;
break;
}
if($found > -1){
$results[$found]['relevance'][] = $person['relevance'];
$results[$found]['count'] += $person['count'];
} else {
$results[] = $person;
}
}
foreach($results as $i => $res)
$results[$i]['relevance'] = array_sum($res['relevance']) / count($res['relevance']);
return $results;
}

Group rows of a multidimensional array and form comma-separated values within each group

I want to combine arrays having same category id and question id.
Sample input:
$array = [
[
'category_id' => 1,
'question_id' => 1,
'option_id' => 2,
'title' => 'Do you wear glasses?',
'answer' => 'no'
],
[
'category_id' => 1,
'question_id' => 2,
'option_id' => 3,
'title' => 'Your hobbies ?',
'answer' => 'movies'
],
[
'category_id' => 1,
'question_id' => 4,
'option_id' => 8,
'title' => 'what is your status?',
'answer' => 'single'
],
[
'category_id' => 1,
'question_id' => 2,
'option_id' => 1,
'title' => 'Your hobbies ?',
'answer' => 'travel'
],
];
The 2nd and 4th arrays contain the same question (same category id and same question id), so I would like to have their answer values merged together as a comma-separated string.
Desired result:
Array(
[0] => Array
(
[category_id] => 1
[question_id] => 1
[option_id] => 2
[title] => Do you wear glasses?
[answer] => no
)
[1] => Array
(
[category_id] => 1
[question_id] => 2
[option_id] => 3
[title] => Your hobbies ?
[answer] => movies,travel
)
[2] => Array
(
[category_id] => 1
[question_id] => 4
[option_id] => 8
[title] => what is your status?
[answer] => single
)
)
It is okay that the option id and title are overwritten while grouping because I am not using the option id and the title values will be identical within each group.
maybe something like this could work, not sure if there's a better way to do it tho:
new_array=array();
foreach($source_array as $e){
$insert=1;
foreach($new_array as $n)
if(array_search($e['title'], $n)==false){
$n['answer'].=", ".$e['answer'];
$insert=0;
}
}
if($insert){
$new_array[]=$e;
}
}
For an example array
Array
(
[0] => Array
(
[category_id] => 1
[question_id] => 1
)
[1] => Array
(
[category_id] => 2
[question_id] => 2
)
[2] => Array
(
[category_id] => 1
[question_id] => 1
)
)
You could do something like this as an illustration
// Define the array to work on
$array = array( array( 'category_id' => 1, 'question_id'=> 1), array( 'category_id' => 2, 'question_id' => 2), array( 'category_id' => 1, 'question_id' => 1));
// Initialize the result array containing only unique question_id/category_id combinations
$unique_array = array();
foreach ($array as $key) {
if (!count($unique_array)) {
$unique_array[] = $key;
} else {
$unique = 1;
foreach ($unique_array as $check) {
if ( $check['category_id'] == $key['category_id'] && $check['question_id'] == $key['question_id'] ) {
$unique = 0;
}
}
if ( $unique ) {
$unique_array[] = $key;
}
}
}
print_r($unique_array);
The output of the last print_r would be
Array
(
[0] => Array
(
[category_id] => 1
[question_id] => 1
)
[1] => Array
(
[category_id] => 2
[question_id] => 2
)
)
The reason I ask if order matters, is that if it doesn't matter, you can sort your array first, and then only compare each one to its previous sibling:
$source=array(array("cat_id"=>1,"ques_id"=>1,"opt_id"=>2,"title"=>"cid:1, qid:1, oid:2","answer"=>"whatever"),array("cat_id"=>1,"ques_id"=>2,"opt_id"=>3,"title"=>"cid:1, qid:2, oid:3","answer"=>"whatever"),array("cat_id"=>1,"ques_id"=>4,"opt_id"=>8,"title"=>"cid:1, qid:4, oid:8","answer"=>"whatever"),array("cat_id"=>1,"ques_id"=>2,"opt_id"=>1,"title"=>"cid:1, qid:2, oid:1","answer"=>"whtvr"));
print_r($source); // just to debug
usort($source,function($a,$b){
if($a["cat_id"]<$b["cat_id"])
return -1;
elseif($a["cat_id"]>$b["cat_id"])
return 1;
elseif($a["ques_id"]<$b["ques_id"])
return -1;
elseif($a["ques_id"]>$b["ques_id"])
return 1;
elseif($a["opt_id"]<$b["opt_id"])
return -1;
elseif($a["opt_id"]>$b["opt_id"])
return 1;
else
return 0;
});
$source=array_reduce($source,function(&$a,$b){
if(empty($a))
{
$a=array($b);
}
else
{
$cache=array_pop($a);
if($cache["cat_id"]==$b["cat_id"] && $cache["ques_id"]==$b["ques_id"])
{
$cache["answer"].=", ".$b["answer"];
$a[]=$cache;
}
else
{
$a[]=$cache;
$a[]=$b;
}
}
return $a;
},array());
print_r($source);
Outputs:
// first print_r
Array
(
[0] => Array
(
[cat_id] => 1
[ques_id] => 1
[opt_id] => 2
[title] => cid:1, qid:1, oid:2
[answer] => whatever
)
[1] => Array
(
[cat_id] => 1
[ques_id] => 2
[opt_id] => 3
[title] => cid:1, qid:2, oid:3
[answer] => whatever
)
[2] => Array
(
[cat_id] => 1
[ques_id] => 4
[opt_id] => 8
[title] => cid:1, qid:4, oid:8
[answer] => whatever
)
[3] => Array
(
[cat_id] => 1
[ques_id] => 2
[opt_id] => 1
[title] => cid:1, qid:2, oid:1
[answer] => whtvr
)
)
// second print_r
Array
(
[0] => Array
(
[cat_id] => 1
[ques_id] => 1
[opt_id] => 2
[title] => cid:1, qid:1, oid:2
[answer] => whatever
)
[1] => Array
(
[cat_id] => 1
[ques_id] => 2
[opt_id] => 1
[title] => cid:1, qid:2, oid:1
[answer] => whtvr, whatever
)
[2] => Array
(
[cat_id] => 1
[ques_id] => 4
[opt_id] => 8
[title] => cid:1, qid:4, oid:8
[answer] => whatever
)
)
Please be noted that you stated in your comment that option_id is irrelevant, so I didn't replace it; you can replace that too inside the anonymous function inside array_reduce if you need to.
$data = array();
//$new is the array in which you have data originally
foreach($new as $arrayK => $arrayV){
if(!isset($data[$arrayV['category_id']][$arrayV['question_id']]))
$data[$arrayV['category_id']][$arrayV['question_id']] = $arrayV;
else{
$option = $data[$arrayV['category_id']][$arrayV['question_id']]['option_id'] . ',' . $arrayV['option_id'];
$data[$arrayV['category_id']][$arrayV['question_id']]['option_id'] = $option;
$answer = $data[$arrayV['category_id']][$arrayV['question_id']]['answer'] . ',' . $arrayV['answer'];
$data[$arrayV['category_id']][$arrayV['question_id']]['answer'] = $answer;
}
}
$data will have the required data in mentioned format
Both answer and option will be comma seperated
foreach($arr as $k=>$a)
{
$common[$k] = search($arr,'category_id',$a['category_id'],'question_id',$a['question_id']);
$answers = array_map(function($item) { return $item['answer']; }, $common[$k]);
$options = array_map(function($item) { return $item['option_id']; }, $common[$k]);
foreach($common[$k] as $temp)
{
$finalAns = $temp;
$finalAns['answer'] = implode(",",$answers);
$finalAns['option_id'] = implode(",",$options);
}
$final[] = $finalAns;
}
$final = array_map("unserialize", array_unique(array_map("serialize", $final)));
echo "<pre>";
print_r($final);
Put Below function in your common function file or in same file.
function search($array, $key, $value, $key1, $value1)
{
$results = array();
if (is_array($array))
{
if (isset($array[$key]) && $array[$key] == $value && isset($array[$key1]) && $array[$key1] == $value1)
{
$results[] = $array;
}
foreach ($array as $subarray)
$results = array_merge($results, search($subarray, $key, $value,$key1,$value1));
}
return $results;
}
Your output would be
Array
(
[0] => Array
(
[category_id] => 1
[question_id] => 1
[option_id] => 2
[title] => Do you wear glasses?
[answer] => no
)
[1] => Array
(
[category_id] => 1
[question_id] => 2
[option_id] => 3,1
[title] => Your hobbies ?
[answer] => movies,travel
)
[2] => Array
(
[category_id] => 1
[question_id] => 4
[option_id] => 8
[title] => what is your status?
[answer] => single
)
)
There is no reason for convoluted logic or multiple loops.
Each group needs to have a unique identifier. Although the asker states that question_id is enough, you can guarantee uniqueness by combining question_id and category_id as a delimited string. Use this "composite identifier" as the first-level key while pushing data into the result array.
When a composite key is re-encountered ), then do not both to save all data -- only append data to the desired element(s).
When finished iterating, re-index the result array to remove the temporary composite keys (if you wish).
Code: (Demo)
$result = [];
foreach ($array as $row) {
$compositeKey = $row['category_id'] . '_' . $row['question_id'];
if (!isset($result[$compositeKey])) {
$result[$compositeKey] = $row;
} else {
$result[$compositeKey]['answer'] .= ",{$row['answer']}";
}
}
var_export(
array_values(
$result
)
);
P.s. Typically, it is better to form subarrays instead of comma-delimited strings. Subarrays allows better access to individual values and flexibility in presentation. If you ever change your mind about how to present the values, you'd otherwise need to remove or replace the commas and print something else. Save the hassle, leave presentation to your (view) presentation loop and implode the subarray values exactly as you wish.

PHP Reorder array to reflect parent / id hierarchy

How do I rearrange the following array
[0] => Array
(
[id] => 1
[parent_id] => 0
[name] => Accueil
)
[1] => Array
(
[id] => 2
[parent_id] => 0
[name] => Exposants
)
[2] => Array
(
[id] => 3
[parent_id] => 0
[name] => Visiteurs
)
[3] => Array
(
[id] => 4
[parent_id] => 0
[name] => Medias
)
[4] => Array
(
[id] => 5
[parent_id] => 0
[name] => Activités
)
[5] => Array
(
[id] => 6
[parent_id] => 1
[name] => Contact
)
[6] => Array
(
[id] => 7
[parent_id] => 3
[name] => Partenaires
)
[7] => Array
(
[id] => 8
[parent_id] => 2
[name] => News
)
So I come up with an array that reflects the hierarchy as shown by the id and parent_id fields? The array key is the ID field of array elements are parents. Inside this array is each time a child array that has its ID field as the key. Sample:
[1] => Array
(
[name] => Accueil
[children] => array(
[0] => bla,
[3] => bla2
)
)
[2] => Array
(
[name] => Something
[children] => array(
[4] => bla3,
)
)
Works for any depth and allows children to precede parents:
<?php
$p = array(0 => array());
foreach($nodes as $n)
{
$pid = $n['parent_id'];
$id = $n['id'];
if (!isset($p[$pid]))
$p[$pid] = array('child' => array());
if (isset($p[$id]))
$child = &$p[$id]['child'];
else
$child = array();
$p[$id] = $n;
$p[$id]['child'] = &$child;
unset($p[$id]['parent_id']);
unset($child);
$p[$pid]['child'][] = &$p[$id];
}
$nodes = $p['0']['child'];
unset($p);
?>
Use var_dump on the $nodes result to see the structure. It is close to what you suggested. The major difference is that the keys are not the ids.
You could make this more DRY, but it's a quick and dirty way to handle it. Also, you could remove 6 lines if you could guarantee that each child record has a valid parent record and that the valid parent record precedes the child record in the original array.
$sorted = array();
foreach( $orig_ary as $item ) {
if ( $item['parent_id'] === 0 ) {
if ( !array_key_exists( $item['id'], $sorted ) ) {
$sorted[ $item['id'] ] = array(
'name' => '',
'children' => array()
);
}
$sorted[ $item['id'] ]['name'] = $item['name'];
} else {
if ( !array_key_exists( $item['parent_id'], $sorted ) ) {
$sorted[ $item['parent_id'] ] = array(
'name' => '',
'children' => array()
);
}
$sorted[ $item['parent_id'] ]['children'][ $item['id'] ] = $item['name'];
}
}

Categories