I have two identical arrays:
$array1 = array(
array(
'start' => 1,
'value' => 10
),
array(
'start' => 8,
'value' => 4
),
array(
'start' => 4,
'value' => 8
),
array(
'value' => 5,
)
);
$array2 = array(
array(
'start' => 1,
'value' => 10
),
array(
'start' => 8,
'value' => 4
),
array(
'start' => 4,
'value' => 8
),
array(
'value' => 5,
)
);
I need to merge and sort them in ascending order:
$array1 = array_merge($array1, $array2);
usort($array1, function($value1, $value2) {
if (!array_key_exists('start', $value1) || !array_key_exists('start', $value2)) {
return 0;
}
return $value1['start'] - $value2['start'];
});
However, this doesn't work, and the ordering is incorrect:
Array
(
[0] => Array
(
[start] => 4
[start] => 8
)
[1] => Array
(
[start] => 8
[value] => 4
)
[2] => Array
(
[amount] => 5
)
[3] => Array
(
[start] => 1
[value] => 10
)
[4] => Array
(
[value] => 5
)
[5] => Array
(
[start] => 1
[value] => 10
)
[6] => Array
(
[start] => 4
[value] => 8
)
[7] => Array
(
[start] => 8
[value] => 4
)
)
It should ideally place all items without a start attribute to the start of the array and all items with a start attribute following those in ascending order.
If I remove the arrays that contain no start attribute, it seems to work perfectly. But I need to keep those items without a start attribute. Is there anything I can do with my sort to go around this issue without going through the merged array, removing those that have no start and replacing them after the sort? Ideally I'd love to understand what is happening here to make it fail.
To place the elements without an start key at the front, you have to handle them diffrently in your compare function.
You could try something like this
usort($array1, function($value1, $value2) {
if (!isset($value1['start']) && !isset($value2['start'])) {
return 0;
} else if (!isset($value1['start'])) {
return -1;
} else if (!isset($value2['start'])) {
return 1;
}
return $value1['start'] - $value2['start'];
});
Related
I need to convert the below 2d array in to specified 2d array format. Array contains multiple parent and multiple child array. Also, have tried to convert the code, but am not getting the expected output.
This is the code what i have tried,
$a1 = array(
'0' =>
array(
'banner_details' =>
array(
'id' => 2,
'section_id' => 24
),
'slide_details' =>
array(
0 => array(
'id' => 74,
'name' => 'Ads1'
),
1 => array(
'id' => 2,
'name' => 'Ads2'
)
)
),
'1' =>
array(
'banner_details' =>
array(
'id' => 106,
'section_id' => 92
),
'slide_details' =>
array(
0 => array(
'id' => 2001,
'name' => 'Adv1'
),
1 => array(
'id' => 2002,
'name' => 'Adv2'
)
)
)
);
$s = [];
for($i = 0; $i<2; $i++) {
foreach($a1[$i]['slide_details'] as $vs){
$s[] = $vs;
}
}
My output:
Array
(
[0] => Array
(
[id] => 74
[name] => Ads1
)
[1] => Array
(
[id] => 2
[name] => Ads2
)
[2] => Array
(
[id] => 2001
[name] => Adv1
)
[3] => Array
(
[id] => 2002
[name] => Adv2
)
)
Expected output:
Array
(
[24] => Array
(
[0] => 74
[1] => 2
)
[92] => Array
(
[0] => 2001
[1] => 2002
)
)
please check the above code and let me know.
Thanks,
You can apply next simple foreach loop with help of isset() function:
foreach($a1 as $data){
if (isset($data['banner_details']['section_id'])){
$s[$data['banner_details']['section_id']] = [];
if (isset($data['slide_details'])){
foreach($data['slide_details'] as $row){
$s[$data['banner_details']['section_id']][] = $row['id'];
}
}
}
}
Demo
If you know that indexes like banner_details or slide_details or section_id will be there always then you can skip isset() in if statements.
You can use array_column function for simple solution:
$result = [];
foreach ($a1 as $item)
{
$result[$item['banner_details']['section_id']] = array_column($item['slide_details'], 'id');
}
var_dump($result);
I have an array like this
Array
(
[0] => Array
(
[id] => 1
[category_name] => One
[parent_id] =>
[children_recursive] => Array
(
)
)
[1] => Array
(
[id] => 2
[category_name] => Two
[parent_id] =>
[children_recursive] => Array
(
)
)
[2] => Array
(
[id] => 3
[category_name] => Three
[parent_id] =>
[children_recursive] => Array
(
[0] => Array
(
[id] => 17
[category_name] => Three and one
[parent_id] => 3
[children_recursive] => Array
(
)
)
[1] => Array
(
[id] => 19
[category_name] => Three and two
[parent_id] => 3
[children_recursive] => Array
(
[0] => Array
(
[id] => 21
[category_name] => Three and two and one
[parent_id] => 19
[children_recursive] => Array
(
)
)
)
)
[2] => Array
(
[id] => 20
[category_name] => Three and three
[parent_id] => 3
[children_recursive] => Array
(
)
)
)
)
[3] => Array
(
[id] => 4
[category_name] => Four
[parent_id] =>
[children_recursive] => Array
(
[0] => Array
(
[id] => 18
[category_name] => Four and one
[parent_id] => 4
[children_recursive] => Array
(
)
)
)
)
)
What I want to from this array
One
Two
Three
Three >> Three and one
Three >> Three and two
Three >> Three and two >> Three and two and one
Three >> Three and three
Four
Four >> Four and one
What I have tried
$category = myarray;
renderNode($category);
function renderNode($node) {
foreach($node as $cat){
echo $cat['category_name'].'<br >';
if(!empty($cat[children_recursive'])){
renderNode($cat[children_recursive']);
}
}
}
And My output is
One
Two
Three
Three and one
Three and two
Three and two and one
Three and three
Four
Four and one
Edit
here is the full array list using var_export so you can just copay and paste
array (
0 =>
array (
'id' => 1,
'category_name' => 'One',
'parent_id' => NULL,
'children_recursive' =>
array (
),
),
1 =>
array (
'id' => 2,
'category_name' => 'Two',
'parent_id' => NULL,
'children_recursive' =>
array (
),
),
2 =>
array (
'id' => 3,
'category_name' => 'Three',
'parent_id' => NULL,
'children_recursive' =>
array (
0 =>
array (
'id' => 17,
'category_name' => 'Three and one',
'parent_id' => 3,
'children_recursive' =>
array (
),
),
1 =>
array (
'id' => 19,
'category_name' => 'Three and two',
'parent_id' => 3,
'children_recursive' =>
array (
0 =>
array (
'id' => 21,
'category_name' => 'Three and two and one',
'parent_id' => 19,
'children_recursive' =>
array (
),
),
),
),
2 =>
array (
'id' => 20,
'category_name' => 'Three and three',
'parent_id' => 3,
'children_recursive' =>
array (
),
),
),
),
3 =>
array (
'id' => 4,
'category_name' => 'Four',
'parent_id' => NULL,
'children_recursive' =>
array (
0 =>
array (
'id' => 18,
'category_name' => 'Four and one',
'parent_id' => 4,
'children_recursive' =>
array (
),
),
),
),
)
Something like that:
function getValues($array, $prefix = '')
{
$values = [];
foreach ($array as $value) {
$values[] = $prefix . $value['category_name'];
if (!empty($value['children_recursive'])) {
$values = array_merge($values, getValues($value['children_recursive'], $prefix . $value['category_name'] . ' >> '));
}
}
return $values;
}
implode('<br>', getValues($array));
You can use RecursiveArrayIterator. You need to extend it like this:
class RecursiveChildrenIterator extends RecursiveArrayIterator
{
public function hasChildren()
{
return !empty($this->current()['children_recursive']);
}
public function getChildren()
{
return new static($this->current()['children_recursive']);
}
}
Having this class you can simply loop with one foreach:
$iterator = new RecursiveIteratorIterator(
new RecursiveChildrenIterator($array),
RecursiveIteratorIterator::SELF_FIRST
);
$result = [];
$current = [];
foreach ($iterator as $item) {
$current[$iterator->getDepth()] = $item['category_name'];
if (!$iterator->hasChildren()) {
$result[] = implode(
'>>',
array_slice($current, 0, $iterator->getDepth() + 1)
);
}
}
Take a notice on RecursiveIteratorIterator::SELF_FIRST flag passed to RecursiveIteratorIterator.
Here is working demo.
Addition:
I actually misread you desired array, so to get the one you wanted remove the condition:
foreach ($iterator as $item) {
$current[$iterator->getDepth()] = $item['category_name'];
$result[] = implode(
'>>',
array_slice($current, 0, $iterator->getDepth() + 1)
);
}
Here is working demo.
You can read more about iterators.
$category = myarray;
renderNode($category);
function renderNode($parent_category_name = '' ,$node) {
foreach($node as $cat){
echo $parent_category_name.$cat['category_name'].'<br >';
if(!empty($cat[children_recursive'])){
renderNode($parent_category_name .$cat['category_name'] ." >> ", $cat[children_recursive']);
}
}
}
I have this array (it's just a part of it). 6 = question ID, optionIDs = possible answers.
Array
(
[3] => Array
(
[0] => 6
[1] => Array
(
[0] => Array
(
[optionID] => 16
[isCorrect] => 0
)
[1] => Array
(
[optionID] => 14
[isCorrect] => 1
)
[2] => Array
(
[optionID] => 15
[isCorrect] => 0
)
[3] => Array
(
[optionID] => 17
[isCorrect] => 0
)
)
)
[7] => Array
(
[0] => 6
[1] => Array
(
[0] => Array
(
[optionID] => 16
[isCorrect] => 0
)
[1] => Array
(
[optionID] => 15
[isCorrect] => 0
)
[2] => Array
(
[optionID] => 17
[isCorrect] => 0
)
[3] => Array
(
[optionID] => 14
[isCorrect] => 1
)
)
)
)
I'm trying to merge redundant questions (6 and 6) with array_map:
$unique = array_map('unserialize', array_unique(array_map('serialize', $quizQuestionArray)));
And it works as long as optionIDs are in the same order. But in some cases (like here) they are shuffled (16,14,15,17) (16,15,17,14). Is there a way to keep them shuffled and remove duplicate questions?
array_map-serialize is a pretty crude way to deduplicate an array. You should be using something like this instead:
$dupeIds = [];
$array = array_filter($array, function ($item) use (&$dupeIds) {
$keep = !isset($dupeIds[$item[0]]);
$dupeIds[$item[0]] = true;
return $keep;
});
You will need to sort them to the same order before applying you array_map() function. You can use the uasort() function and supply your own comparison function like this:
// Example array
$array = array(
3 => array(
0 => 6,
1 => array(
0 => array(
'optionID' => 16,
'isCorrect' => 0
),
1 => array(
'optionID' => 14,
'isCorrect' => 1
),
2 => array(
'optionID' => 15,
'isCorrect' => 0
),
3 => array(
'optionID' => 17,
'isCorrect' => 0
),
)
),
7 => array(
0 => 6,
1 => array(
0 => array(
'optionID' => 16,
'isCorrect' => 0
),
1 => array(
'optionID' => 15,
'isCorrect' => 0
),
2 => array(
'optionID' => 17,
'isCorrect' => 0
),
3 => array(
'optionID' => 14,
'isCorrect' => 1
),
)
)
);
// You can supply parts of an array to uasort()
// uasort() will modify your array but keep your keys.
uasort($array[3][2], 'sort_by_optionid');
uasort($array[7][3], 'sort_by_optionid');
function sort_by_optionid($a, $b) {
if ($a['optionID'] === $b['optionID']) {
return 0;
} else if ($a['optionID'] > $b['optionID']) {
return 1;
} else {
return -1;
}
}
// Done.
Now the keys are preserved and you can easily array_map() to find the duplicates and then sort again back to the original state according to the keys. E.g. with uksort()
I have search for a solution for this but couldn't find anything giving me a "straight" multidimensional array back. Flatten is probably not the solution as long as i want to preserve the original sub structure?
In additional i want to summarize qty when the key is repeating.
This is my original array:
Array
(
[60002] => Array
(
[50001] => Array
(
[50002] => Array
(
[10001] => Array
(
[flag] => B
[qty] => 1
)
[10002] => Array
(
[flag] => B
[qty] => 1
)
[10003] => Array
(
[flag] => B
[qty] => 2
)
[flag] => M
[qty] => 1
)
[flag] => M
[qty] => 1
)
[flag] => G
[qty] => 1
)
[10001] => Array
(
[flag] => B
[qty] => 1
)
)
What i basically want is to create a new array looking like this:
Array
(
[10001] => Array
(
[flag] => B
[qty] => 2
)
[10002] => Array
(
[flag] => B
[qty] => 1
)
[10003] => Array
(
[flag] => B
[qty] => 2
)
[50001] => Array
(
[flag] => M
[qty] => 1
)
[50002] => Array
(
[flag] => M
[qty] => 1
)
[60002] => Array
(
[flag] => G
[qty] => 1
)
)
This is tested.
The key is intval().
$value['qty'] += intval($newArray[$key]['qty']);
If the [$key]['qty'] does not exist the intval() will return a zero. This is much faster than using an if else to check if a [$key]['qty'] already exists.
The only possible problem I could anticipate is if the Flag value is different when the key value is the same:
[10001] => Array(
[flag] => M
[qty] => 1
),
[10001] => Array(
[flag] => B
[qty] => 1
)
When this is an issue I resolve the priority with a logic table in an array.
$priority['M']['B'] = 'M'
$priority['B']['M'] = 'M'
$priority['']['M'] = 'M'
$priority['M'][''] = 'M'
$priority['B'][''] = 'B'
$priority['B'][''] = 'B'
settype($newArray[$key]['flag'],'string');
[$newArray[$key]['flag'] = $priority[$value['flag']][$newArray[$key]['flag']]
Data:
$array = array('60002' => Array('50001' => Array('50002' => Array('10001' => Array('flag' => 'B','qty' => 1),'10002' => Array('flag' => 'B','qty' => 1),'10003' => Array('flag' => 'B','qty' => 2),'flag' => 'M','qty' => 1),'flag' => 'M','qty' => 1),'flag' => 'G','qty' => 1),'10001' => Array('flag' => 'B','qty' => 1));
PHP
$newArray = array();
getValues($data);
function getValues($array){
global $newArray;
foreach ($array as $key => $value){
if(is_numeric($value['qty'])) {
$value['qty'] += intval($newArray[$key]['qty']);
$newArray[$key] = array('flag'=>$value['flag'],'qty'=>$value['qty']);
}
if (gettype($value) != 'array'){return;}
getValues($value);
}
}
ksort($newArray);
var_export($newArray);
Result:
array (
10001 =>
array (
'flag' => 'B',
'qty' => 2,
),
10002 =>
array (
'flag' => 'B',
'qty' => 1,
),
10003 =>
array (
'flag' => 'B',
'qty' => 2,
),
50001 =>
array (
'flag' => 'M',
'qty' => 1,
),
50002 =>
array (
'flag' => 'M',
'qty' => 1,
),
60002 =>
array (
'flag' => 'G',
'qty' => 1,
),
)
This seemed to work:
function extractArray(array $source, array &$destination, $originalIndex)
{
foreach($source as $index => $value)
{
if(is_array($value))
extractArray($value, $destination, $index);
else
$destination[$originalIndex][$index] = $value;
}
}
$test = array(
60002 => array
(
50001 => array
(
50002 => array
(
10001 => array
(
'flag' => 'B',
'qty' => 1
),
10002 => array
(
'flag' => 'B',
'qty' => 1
),
10003 => array
(
'flag' => 'B',
'qty' => 2
),
'flag' => 'M',
'qty' => 1
),
'flag' => 'M',
'qty' => 1
),
'flag' => 'G',
'qty' => 1
),
10001 => array
(
'flag' => 'B',
'qty' => 1
)
);
$new = array();
foreach($test as $index => $value)
extractArray($value, $new, $index);
var_dump($new);
die();
You can use a recursive approach to iterate over all levels of the array. For each item you check that it is an array and if it has any of the keys you want checked, add the array consisting of the found attributes.
function flattenArray($array, $keysToCheck) {
$result = array();
foreach($array as $item) {
// check if the current array item is a candidate to
// be added to the flattened array
if(is_array($item)) {
$foundAttributes = array();
foreach($item as $key=>$value) {
if(in_array($key, $keysToCheck) {
$foundAttributes[$key] = $value;
}
}
// we found at least one matching attribute
if(count($foundAttributes)) {
array_push($result, $foundAttributes);
}
// recursively go to the next level and merge the results from there
$result = array_merge($result, flattenArray($item, $keysToCheck);
}
}
return $result;
}
// usage example
$flattenedArray = flattenArray($originalArray, array('flag', 'qty'));
The above solution allows you to customise it for other type of objects, by passing different $keysToCheck arguments to the function.
If you also need the flattened array sorted, you can use usort() to achieve this.
Please pardon any syntax errors, I don't have a PHP interpreter at hand.
I have 2 multidimensional arrays that I am working with:
$arr1 =
Array
([type] => characters
[version] => 5.6.7.8
[data] => Array
([Char1] => Array
([id] => 1
[name] =>Char1
[title] =>Example
[tags] => Array
([0] => DPS
[1] => Support))
[Char2] => Array
([id] => 2
[name] =>Char2
[title] =>Example
[tags] => Array
([0] => Tank
[1] => N/A)
)
)
etc...
$arr2=
Array
([games] => Array
([gameId] => 123
[gameType => Match
[char_id] => 1
[stats] => Array
([damage] => 55555
[kills] => 5)
)
([gameId] => 157
[gameType => Match
[char_id] => 2
[stats] => Array
([damage] => 12642
[kills] => 9)
)
etc...
Basically, I need almost all the data in $arr2... but only the Char name from $arr1. How could I merge or add the $arr1['name'] key=>value into $arr2 where $arr1['id'] is equal to $arr2['char_id'] as the "id" field of each array is the same number.
I've attempted using array_merge and array_replace, but I haven't come up with any working solutions. This is also all data that I am receiving from a 3rd party, so I have no control on initial array setup.
Thanks for any help or suggestions!
Actually, this is quite straighforward. (I don't think there a built-in function that does this.)
Loop $arr2 and under it loop also $arr1. While under loop, just add a condition that if both ID's match, add that particular name to $arr2. (And use some referencing & on $arr2)
Consider this example:
// your data
$arr1 = array(
'type' => 'characters',
'version' => '5.6.7.8',
'data' => array(
'Char1' => array(
'id' => 1,
'name' => 'Char1',
'title' => 'Example',
'tags' => array('DPS', 'Support'),
),
'Char2' => array(
'id' => 2,
'name' => 'Char2',
'title' => 'Example',
'tags' => array('Tank', 'N/A'),
),
),
);
$arr2 = array(
'games' => array(
array(
'gameId' => 123,
'gameType' => 'Match',
'char_id' => 1,
'stats' => array('damage' => 55555, 'kills' => 5),
),
array(
'gameId' => 157,
'gameType' => 'Match',
'char_id' => 2,
'stats' => array('damage' => 12642, 'kills' => 9),
),
),
);
foreach($arr2['games'] as &$value) {
$arr2_char_id = $value['char_id'];
// loop and check against the $arr1
foreach($arr1['data'] as $element) {
if($arr2_char_id == $element['id']) {
$value['name'] = $element['name'];
}
}
}
echo '<pre>';
print_r($arr2);
$arr2 should look now like this:
Array
(
[games] => Array
(
[0] => Array
(
[gameId] => 123
[gameType] => Match
[char_id] => 1
[stats] => Array
(
[damage] => 55555
[kills] => 5
)
[name] => Char1 // <-- name
)
[1] => Array
(
[gameId] => 157
[gameType] => Match
[char_id] => 2
[stats] => Array
(
[damage] => 12642
[kills] => 9
)
[name] => Char2 // <-- name
)
)
)
Iterate over $arr2 and add the data to it from the matching $arr1 array value:
$i = 0;
foreach($arr2['games'] as $arr2Game){
$id = $arr2Game['char_id'];
$arr2['games'][$i]['name'] = $arr1['data'][$id]['name'];
$i++;
}
Have not tested this code.
If I'm understanding you correctly, you want to add a name index to each of the arrays within the $arr2['games'] array.
foreach($arr2['games'] as $key => $innerArray)
{
$arr2['games'][$key]['name'] = $arr1['data']['Char'.$innerArray['char_id']]['name'];
}