How to sort an array based on input array? - php

I'm having trouble sorting an array according to another array. I've tried usort, uksort and uasort but I'm getting nowhere. Other questions on stackoverflow are not directly applicable here, as my array structure is different. I want to sort this multidimensional array:
$main = Array (
[Technology] => Array ()
[World] => Array ()
[Europe] => Array ()
)
By using this index-array:
$index = Array (
[0] => Europe
[1] => Technology
[2] => World
)
Basically, in this example I would want Europe to come first in the $main array, Technology second and World third, as this is their positioning in the $index array. How do I do that? (Please disregard little syntax errors in the arrays above)

$main_sort = array()
foreach ($index as $key => $value) {
if ($main [$value]) $main_sorted [$value] = $main [$value];
}
Simply loop through the $index array and map those values to a new array using the values from the $main array.

Given $index and $main,
uksort($main, function ($k, $k2) use ($index) {
return array_search($k, $index) - array_search($k2, $index);
});
Array will be sorted according to keys specified in $index. Behavior of not-matched keys is unspecified.

This solution works if you don't have any value in $index which is not a key in $main (as is the case in your example):
$sorted = array_merge(array_flip($index), $main);
If the values of $index are a superset of the keys of $main, a possible solution is:
$sorted = array_intersect_assoc(array_merge(array_flip($index), $main), $main);
Keep in mind that letting PHP functions work on arrays is much faster than doing so "explicitly"

Related

Get value from different arrays

I'm getting started with PHP and I have some troubles finding a way to output values from multiples arrays sent from an external site.
I did a foreach and the code that is printed looks like this :
Array
(
[id] => 1
[title] => Title 1
)
Array
(
[id] => 2
[title] => Title 2
)
Array
(
[id] => 3
[title] => Title 3
)
Any idea how I could get every id (1,2,3) in an echo?
Let me know if you need more informations!
Thanks a lot!
If you just want to echo all the id's in all the arrays, a simple solution would be:
foreach ([$array1, $array2, $array3] as $arr) {
echo $arr['id'];
}
A better solution would probably to create one main array first:
$mainArray = [];
and every time you get a new array, you just push them to the main array:
$mainArray[] = $array1;
$mainArray[] = $array2;
// ... and so on
Then you'll have a multi dimensional array and can loop them with:
foreach ($mainArray as $arr) {
echo $arr['id'];
}
Which solution that works best depends on how you get the arrays and how many they are.
Note: Using array_merge() as others have suggested will not work in this case, since all the arrays have the same keys. From the documentation on array_merge(): "If the input arrays have the same string keys, then the later value for that key will overwrite the previous one."
As you can do:
$array = array_merge_recursive($arr1, $arr2, $arr3);
var_dump($newArray['id']);
echo implode(",", $newArray['id']);
A demo code is here

How do I reorganize an array in PHP?

I am trying to figure out how to reorganize an array..
I have a multidimensional array(Ill call that original_array) and I would like to take the first array within original_array and set the values as keys in a new array. I also want to take the values of the second array in original_array and make them keys and then set the values of the third array in original_array as the values for those keys.
Here is an example of original_array:
Array (
[id] => Array (
[0] => 1
[1] => 3
)
[reward] => Array (
[0] => Movie
[1] => Trip
)
[cost] => Array (
[0] => 50
[1] => 200
)
)
Basically what I would like to do is look like this:
Array (
[1] => Array (
[Movie] => 50
)
[3] => Array (
[Trip] => 200
)
)
Is there a simple and elegant way to merge these like this?
I have spent hours trying to figure this out using array_merge, array_merge_recursive.. etc. And have search SO far and wide for a similar questions, but I haven't found anything that does what I am after.
I was able to correctly combine the 2nd and 3rd arrays in original_array with array_combine. But, I am at a loss as how to combine that result with the 1st array's values in original_array.
Thanks in advance to any help!
Well, the dirty way would be just use combine array functions like array_combine with the input:
$new_array = array_combine(
$array['id'], // parent keys
// combine chunked combined sub keys :p
array_chunk(array_combine($array['reward'], $array['cost']), 1, true)
);
There may be some incantation of array_*() merging functions that could produce what you're looking for, but it is far easier to just iterate over the original array's [id] sub-array and use its values to create new sub-array keys in a different output array.
// To hold your output
$output = array();
// Iterate the original array's [id] sub-array
foreach ($original['id'] as $idxkey => $newkey) {
// Add a sub-array using $newkey to the output array
$output[$newkey] = array(
// Using the index (not value), retrieve the corresponding reward
// value to use as the new array key
// and corresponding cost to use as the new subarray value
$original['reward'][$idxkey] => $original['cost'][$idxkey]
);
}
Here is a demonstration: https://3v4l.org/2pac3
This should work for you:
First you can get the keys for the main array into a separate variable with array_shift(), which will just remove the first element from your array, which is the array holding the keys.
Then use array_map() to loop through both of your subArrays and use reward as key with the cost values as value and return it in an array. At the end you just have to array_combine() your keys $keys with the new created array.
Code:
<?php
$keys = array_shift($arr);
$result = array_combine($keys, array_map(function($k, $v){
return [$k => $v];
}, $arr["reward"], $arr["cost"]));
print_r($result);
?>
You might wanna take a look at BaseArrayHelper from Yii 2.0 Framework.
Although this file is part of a framework it has only very few dependencies and you should be able to use just this file or parts of it in your code with small modifications.
An example for your use case can be found in the index() method.

PHP. Sort array element on top by key

$key = "cat"
$array = array( dog,
bird,
cat,
moon );
Need order like this (by key):
cat, dog, bird, moon.
$key = "cat" , so string "cat" need to be first element of array.
How to do that?
You're not actually sorting, just moving something in the array to the beginning. It might be simpler but here is one way:
array_unshift($array, current(array_splice($array, array_search($key, $array), 1)));
array_search() finds the index of the element that contains $key
array_splice() removes that element
array_unshift() prepends that element to the array
All the above solutions will work fine with the provided input array
$array = array('dog','bird', 'cat','moon');
However if the input array in an associative array, then above solutions will not work. See the changed input array below:
$array = array('frist' => 'foo', 'dog','bird', 'cat','moon', 'cat');
It will be handy to use the following function in case of performance. It does not have overhead of calling too many builtin PHP array functions. Moreover it will work both sequential and associative PHP arrays. See the code segment below:
Function definition
function moveToTop($array, $key){
foreach ($array as $index => $value) ($value != $key) ? $newArray[$index] = $value : '';
array_unshift($newArray, $key);
return $newArray;
}
Function call
moveToTop($array, $key)
Output
Array
(
[0] => cat
[frist] => foo
[1] => dog
[2] => bird
[3] => moon
)

Remove all elements of an array with non-numeric keys

I have an array that looks something like this:
Array
(
[0] => apple
["b"] => banana
[3] => cow
["wrench"] => duck
)
I want to take that array and use array_filter or something similar to remove elements with non-numeric keys and receive the follwoing array:
Array
(
[0] => apple
[3] => cow
)
I was thinking about this, and I could not think of a way to do this because array_filter does not provide my function with the key, and array_walk cannot modify array structure (talked about in the PHP manual).
Using a foreach loop would be appropriate in this case:
foreach ($arr as $key => $value) {
if (!is_int($key)) {
unset($arr[$key]);
}
}
It can be done without writing a loop in one (long) line:
$a = array_intersect_key($a, array_flip(array_filter(array_keys($a), 'is_numeric')));
What it does:
Since array_filter works with values, array_keys first creates a new array with the keys as values (ignoring the original values).
These are then filtered by the is_numeric function.
The result is then flipped back so the keys are keys once again.
Finally, array_intersect_key only takes the items from the original array having a key in the result of the above (the numeric keys).
Don't ask me about performance though.
As of PHP 5.6, it's now possible to use array_filter in a compact form:
array_filter($array, function ($k) { return is_numeric($k); }, ARRAY_FILTER_USE_KEY);
Demo.
This approach is about 20% slower than a for loop on my box (1.61s vs. 1.31s for 1M iterations).
As of PHP 7.4, it's possible to also use short closures::
array_filter($array, fn($k) => is_numeric($k), ARRAY_FILTER_USE_KEY);
Here's a loop:
foreach($arr as $key => $value) {
if($key !== 0 and !intval($key)) {
unset($arr[$key]);
}
}

How to compare arrays and extract the difference?

I have two arrays that I would like to compare and ultimately wind up with a single array with everything combined, having no duplicates. Can someone please tell me which function I should use? There are so many that it's a bit confusing.
$array1[]['name'] = 'Kim, Jones';
$array1[]['name'] = 'Jim, Miller';
array1 is an array I built that I want added to an array coming from the database. The key in the second array is also named "name". Thanks.
EDIT:
I managed to merge these two arrays but I can still see duplicates.
This is what the first array looks like:
Array
(
[0] => Array
(
[WNumber] => ADMIN
[Name] => Tim, Cooley
[Employer] => CalPERS
[Student] => 1
[Perm] => 1
[QA] => 0
[Supervisor] => 1
[RQW] => 0
)
My second array is built like this:
$add_names[]['Name']='Jim, Jones';
I just want to add $add_names to the first array WHERE there are no duplicates.
I'm tempted to sell you on CakePHP, since it has a number of functions that makes this easy in its "Set" class. Your problem is that you have the results in a nested array. A simple "array_unique" does not work in a nested array.
I'd do it the old fashioned way...
$array1[]['name'] = 'Kim, Jones';
$array1[]['name'] = 'Jim, Miller';
$array2[]['name'] = 'Kim, Jones';
$array2[]['name'] = 'Jimbo, Miller';
$array2[]['name'] = 'Jim, Jones';
$new_array=array_merge($array1, $array2);
$out_array = array();
$key_array = array();
foreach($new_array as $i => $row) {
if (empty($key_array[$row['name']])) {
$out_array[] = $row;
}
$key_array[$row['name']] = 1;
}
print_r($out_array);
This code works for me...
I think you'll need to use a combination of array_merge (adds the two arrays together) and array_unique (removes duplicate values).
$resulting_array = array_unique(array_merge($array1, $array2));
Note that array_unique will not work correctly when using multi-dimensional arrays, so if your array data looks the way you put it in your question, you'll have to think of a way around that. One of the comments on the array_unique page suggests serialize'ing all array values before running array_unique on it. Afterwards you'd just run unserialize on all array elements. Note that this can mean a performance hit if you have a big array, so you might want to consider avoiding multi-dimensional arrays in this scenario.
Something like this:
$merged_array = array_merge($array1, $array2);
$serialized_array = array_map("serialize", $merged_array);
$filtered_array = array_unique($serialized_array);
$final_array = array_map("unserialize", $filtered_array);
There isn't a direct function for handling what you are looking for in php, probably you need to write a function for it.
What I understood from your question is that you have 2 arrays :
$a = array( array( 'name' => 'Omid' ), 12 );
$b = array( array( 'name' => 'testing' ) );
and you want to merge them to get
$merge = array( array( 'name' => 'testing' ), 12 );
if that's what you want then you might want to take a look at this comment array merge recursive which leads to this code :
function array_merge_recursive_distinct ( array &$array1, array &$array2 )
{
$merged = $array1;
foreach ( $array2 as $key => &$value )
{
if ( is_array ( $value ) && isset ( $merged [$key] ) && is_array ( $merged [$key] ) )
{
$merged [$key] = array_merge_recursive_distinct ( $merged [$key], $value );
}
else
{
$merged [$key] = $value;
}
}
return $merged;
}
Does php's array_diff() do what you want?
http://us.php.net/manual/en/function.array-diff.php
or more likely array_diff_assoc:
http://us.php.net/manual/en/function.array-diff-assoc.php
Does array_diff work for you?
Description
array array_diff ( array $array1 , array $array2 [, array $ ... ] )
Compares array1 against array2 and returns the difference.

Categories