PHP. Sort array element on top by key - php

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

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

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 sort an array based on input array?

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"

How to convert a 2-dim array of strings into 1-dim array of trimmed, unique values?

I have an array whose values are all arrays of a specific format that looks like this:
Array
(
[0] => Array
(
[0] => '8227'
[1] => ' 8138'
)
[1] => Array
(
[0] => '8227'
[1] => ' 8138'
[2] => ' 7785'
)
)
and I would like to have this:
Array
(
[0] => 8227
[1] => 8138
[2] => 7785
)
How can I do this ?
$result = array();
foreach ($input as $sub) { // Loop outer array
foreach ($sub as $val) { // Loop inner arrays
$val = trim($val);
if (!in_array($val, $result)) { // Check for duplicates
$result[] = $val; // Add to result array
}
}
}
$result = array();
foreach($array as $arr){
$result = array_merge($result, $arr);
}
$result = array_unique($result);
array_merge_recursive() can be used to flatten the array. Then, array_unique() to get the unique values, with array_values() to "reindex" the resultant array.
$flat = call_user_func_array('array_merge_recursive', $subject);
$uniq = array_values(array_unique($flat));
<?php
$array = array(
0 => array(
0 => 8227,
1 => 8138
),
1 => array(
0 => 8227,
1 => 8138,
2 => 7785
)
);
$newArray = array();
array_walk_recursive($array, function($item, $key) use(&$newArray) {
if(!in_array($item, $newArray)) {
$newArray[] = $item;
}
});
print_r($newArray);
?>
I don't like the idea of iterated calls of in_array() since it can cause a bit of drag on big arrays.
Now, my methods to follow are probably not going to set any speed records (I didn't bother to benchmark), but I thought I would post a couple of unorthodox approaches in case they may inspire future readers.
Method #1:
convert the multi-dimensional array to a json string
split the string on all non-digital substrings (this also trims the values)
eliminate duplicates using array_flip()
re-index the resultant array using array_keys() (output values are integer-type)
Method #2:
convert the multi-dimensional array to a json string
extract the words (which in this case include numbers and there aren't any letters to worry about)
eliminate duplicates using array_flip()
reindex the resultant array using array_keys() (output values are integer-type)
Code: (Demo)
$array = [['8227', '8138'], [' 8227', ' 8138', ' 7785']];
echo "regex method: ";
var_export(
array_keys(
array_flip(
preg_split(
'/\D+/',
json_encode($array),
0,
PREG_SPLIT_NO_EMPTY
)
)
)
);
echo "\n\nnon-regex method: ";
var_export(
array_keys(
array_flip(
str_word_count(
json_encode($array),
1,
'0..9'
)
)
)
);
Output:
regex method: array (
0 => 8227,
1 => 8138,
2 => 7785,
)
non-regex method: array (
0 => 8227,
1 => 8138,
2 => 7785,
)
If either of these methods perform well, it will be because they don't make iterated function calls.
p.s. Okay, because I was curious, I just did a very small / unofficial speed test on my two methods and DaveRandom's method (only 1000 iterations using the OP's data - I didn't want to abuse 3v4l.org) and...
Method #1 ran about as fast as Method #2
Both Method #1 and Method #2 ran faster than DaveRandom's method.
Again, I'll state that fabricated tests for micro-optimization may be pointless and real tests should be done on your REAL data IF it is actually important. If you merely prefer the logical flow of another answer on this page, I totally respect that.

Removing elements from an array whose value matches a specified string

I have an array that looks like this:
Array ( [0] => Vice President [1] => [2] => other [3] => Treasurer )
and I want delete the value with other in the value.
I try to use array_filter to filter this word, but array_filter will delete all the empty values, too.
I want the result to be like this:
Array ( [0] => Vice President [1] => [2] => Treasurer )
This is my PHP filter code:
function filter($element) {
$bad_words = array('other');
list($name, $extension) = explode(".", $element);
if(in_array($name, $bad_words))
return;
return $element;
}
$sport_level_new_arr = array_filter($sport_level_name_arr, "filter");
$sport_level_new_arr = array_values($sport_level_new_arr);
$sport_level_name = serialize($sport_level_new_arr);
Can I use another method to filter this word?
array_filter() is the right function. Ensure your callback function has the correct logic.
Try the following:
function other_test($var) {
// returns whether the value is 'other'
return ($var != 'other');
}
$new_arr = array_filter($arr, 'other_test');
Note: if you want to reindex the array, then you could call $new_arr = array_values($new_arr); after the above.
foreach($sport_level_name_arr as $key => $value) {
if(in_array($value, $bad_words)) {
unset($sport_level_name_arr[$key])
}
}
This will create two arrays and will find the difference. In the second array we will put the elements to exclude:
array_values(array_diff($arr,array("other")));
If the callback function returns true, the current value from input is returned into the result array. PHP Manual
So you need to do return true; in your filter(); function instead of return $element; to make sure that no empty values are removed.

Categories