What is the best way to do comparisons in a multidimensional array? in this example I need to check if the indexes 1 and 2 of the internal arrays are repeated and if they are repeated bring the lowest monthly fee that is represented by index 3 of the internal array. What is holding me back is how am I going to compare an array of index 0 with index 1 and so on in a loop. Example:
[
[
0 = > 1,
1 => test 1,
2 => rj,
3 => 1.500
],
[
0 => 2,
1 => test 2,
2 => sp,
3 => 1.700
],
[
0 = > 3,
1 => test 1,
2 => rj,
3 => 1.400
]
]
In this example I would return the last internal array, as it was verified that the index 0 and 2 are the same and its monthly fee is the lowest.
Based on those requirements, the following function should work. It should hopefully be pretty straightforward, but I added some comments to help a bit. The magic indexes are my least-favorite part.
function find_smallest(array $data, string $key): ?array
{
$smallest = null;
foreach ($data as $subArray) {
// Match on key
if ($subArray[1] !== $key) {
continue;
}
// If we didn't find anything yet, store this
if (null === $smallest) {
$smallest = $subArray;
continue;
}
// We previously found this key, compare the third index
if ($smallest[3] >= $subArray[3]) {
$smallest = $subArray;
}
}
return $smallest;
}
Edit
Based on your comments, I reworked this to find all of the smallest items, using the indexes at 1 and 2 to uniquify each item.
function find_all_smallest(array $data): array
{
// Used to form a unique key
$key_delim = '!!';
$all_smallest = [];
foreach ($data as $sub_array) {
$key = $sub_array[1].$key_delim.$sub_array[2];
// If we didn't find anything yet, store this
if (!array_key_exists($key, $all_smallest)) {
$all_smallest[$key] = $sub_array;
continue;
}
// We previously found this key, compare the third index
if ($all_smallest[$key][3] >= $sub_array[3]) {
$all_smallest[$key] = $sub_array;
}
}
// Return the array parts, keys aren't needed
return array_values($all_smallest);
}
Related
I have a single key value array which I would like to loop through and create a seperate array from if certain conditions are met.
For example:
array(
1 => value
2.1 => value
2.2 => value
2.3 => value
2.4 => value
3 => value
)
My variable / condition I want to check is if the item in the array starts with a specific number. For example, if my var = 2, how can I create:
array(
2.1 => value
2.2 => value
2.3 => value
2.4 => value
)
Array filter will do exactly what you need, I just combined that with substr to check if the first char is a 2 and if it is it will return that in the array.
array_filter($array, function($k) {
return substr($k, 0, 1) == '2';
}, ARRAY_FILTER_USE_KEY);
Alternatively if you don't want to one line it you can create a function like the following to do it:
/**
* #param array $array
* #return array
*/
function filterArray(array $array): array
{
$finalData = [];
foreach($array as $key => $value) {
if(substr($key,0,1) == '2') {
$finalData[$key] = $value;
}
}
return $finalData;
}
This question already has answers here:
Group array data on one column and sum data from another column
(5 answers)
Closed 1 year ago.
I have data in MySQL. The data is created by json datas. But I can't change to array from data keys. I want to set this data in order and according to the number of stock.
[
{"size":"36","stock":"1"},
{"size":"37","stock":"2"},
{"size":"38","stock":"1"},
{"size":"40","stock":"1"},
{"size":"36","stock":"1"},
{"size":"37","stock":"3"},
{"size":"38","stock":"2"},
{"size":"39","stock":"3"},
{"size":"40","stock":"2"}
]
I want change to:
array(
'36' => '2',
'37' => '5',
'38' => '3',
'39' => '3',
'40' => '3',
)
I wrote this function but it only returns true and I feel it could be more refined:
function shoesizes($json,$key='size')
{
$array = json_decode($json);
$result = array();
$sum = 0;
$i=0;
foreach((array) $array as $val) {
if(array_key_exists($key, $val)){
$result[$val->$key][] = (array)$val;
}else{
$result[""][] = $val;
}
}
$arrsi = array();
foreach ($result as $k => $v) {
$sum = 0;
foreach ($v as $c => $d) {
$sum += $d['stock'];
}
$arrsi[$k]= $sum;
}
return ksort($arrsi);
}
Decode then iterate the array. If the first occurrence of size store the integer value, if not add the new value to the stored value. When done, sort by the result array keys.
Code: (Demo)
$json = '[
{"size":"36","stock":"1"},
{"size":"37","stock":"2"},
{"size":"38","stock":"1"},
{"size":"40","stock":"1"},
{"size":"36","stock":"1"},
{"size":"37","stock":"3"},
{"size":"38","stock":"2"},
{"size":"39","stock":"3"},
{"size":"40","stock":"2"}
]';
$array = json_decode($json, true);
foreach ($array as $row) {
if (isset($result[$row['size']])) {
$result[$row['size']] += $row['stock'];
} else {
$result[$row['size']] = (int)$row['stock'];
}
}
ksort($result);
var_export($result);
Output:
array (
36 => 2,
37 => 5,
38 => 3,
39 => 3,
40 => 3,
)
Code Review:
ksort() returns a boolean result. By writing return ksort($arrsi);, you can only receive true or false (and false can only happen when there is a failure). http://php.net/manual/en/function.ksort.php Once you write ksort($arrsi); then return $arrsi; then your function returns the desired result.
You declare, but don't use $i so that line can be safely removed.
The first declaration of $sum = 0; isn't necessary because you redeclare the variable later in your second loop.
Your first loop creates an unnecessarily bloated data structure. Assigning the size values as keys is certainly the right step. Storing each set of date as a subarray of the new key is more than what you need. This causes you to have to follow up with a nested loop.
How can I remove all the replicated values in an array, only keeping the remaining unique key/value? array_unique isn't the solution.
For example, I have the following array.
Array
(
[169580] => 1901
[209662] => 2245
[209682] => 1901
)
I want to compare all values in array and remove both [169580] => 1901 and [209682] => 1901 and keep [209662] => 2245 in the array. The 'key' is an unknown value that I cannot search for.
Final result will look like the following:
Array
(
[209662] => 2245
)
One possibility is to group by values, then create the result by taking the key/value pair from groups that have only one key.
// group
foreach ($array as $key => $value) {
$values[$value][] = $key;
}
// filter
foreach ($values as $value => $keys) {
if (count($keys) == 1) $result[$keys[0]] = $value;
}
An approximate equivalent of this algorithm using array functions (similar to what the other answer shows) rather than loops is like this:
// group
$counts = array_count_values($array);
// filter
$result = array_filter($array, function($value) use ($counts) {
return $counts[$value] == 1;
});
You can use a couple array_ functions to accomplish this: array_count_values() to create a frequency count lookup table and array_filter on the original array to remove keys with count !== 1.
$arr = [
"169580" => 1901,
"209662" => 2245,
"209682" => 1901
];
$lookup = array_count_values($arr);
print_r(array_filter($arr, function ($e) use ($lookup) {
return $lookup[$e] == 1;
}));
Output:
Array
(
[209662] => 2245
)
Try it!
I have heterogenous nested arrays (each contains a mix of scalars and arrays, which also may contain scalars and arrays, and so on recursively). The goal is to extract all arrays with the maximum depth. Note this does not mean extracting arrays at the "bottom" of any given sub-array (local maximums), but the greatest depth over all sub-arrays.
For example:
$testArray= array(
'test1' => 'SingleValue1',
'test2' => 'SingleValue2',
'test3' => array(0,1,2),
'test4' => array(array(3,4,array(5,6,7)), array(8,9,array(10,11,12)),13,14),
'test5' => array(15,16,17, array(18,19,20)),
);
In this example, the greatest depth any array occurs at is 3, and there are two arrays at that depth:
array(5,6,7)
array(10,11,12)
The code should find these two. (The [18,19,20] sub-array is not included, for though it's at the greatest depth in its branch, it's at a lesser depth overall.)
I'm not sure where to start. I've tried many things: using foreach in recursive functions, etc., but the end result was always nothing, all elements or the last iterated element. How can this problem be approached? Complete solutions aren't needed, just hints on where to start.
Extended solution with RecursiveIteratorIterator class:
$testArray= array(
'test1' => 'SingleValue1',
'test2' => 'SingleValue2',
'test3' => array(0,1,2),
'test4' => array(array(3,4,array(5,6,7)), array(8,9,array(10,11,12)),13,14),
'test5' => array(15,16,17, array(18,19,20)),
);
$it = new \RecursiveArrayIterator($testArray);
$it = new \RecursiveIteratorIterator($it, \RecursiveIteratorIterator::CHILD_FIRST);
$max_depth = 0;
$items = $deepmost = [];
foreach ($it as $item) {
$depth = $it->getDepth(); // current subiterator depth
if ($depth > $max_depth) { // determining max depth
$max_depth = $depth;
$items = [];
}
if (is_array($item)) {
$items[$depth][] = $item;
}
}
if ($items) {
$max_key = max(array_keys($items)); // get max key pointing to the max depth
$deepmost = $items[$max_key];
unset($items);
}
print_r($deepmost);
The output:
Array
(
[0] => Array
(
[0] => 5
[1] => 6
[2] => 7
)
[1] => Array
(
[0] => 10
[1] => 11
[2] => 12
)
)
You may wrap this approach into a named function and use it for getting the deepmost arrays.
Enjoy! )
Roman's solution seems to work, but I struggle to read that type of method. Here's my version of finding the deepest subarrays.
See my inline comments for explanation of each step. Basically, it checks each array for subarrays, then iterates/recurses when possible, and storea subarrays using the level counter as a key.
My custom function will return an array of arrays.
Code: (Multidimensional Array Demo) (Flat Array Demo) (Empty Array Demo)
function deepestArrays(array $array, int $level = 0, array &$lowest = []): array
{
$subarrays = array_filter($array, 'is_array');
if ($subarrays) { // a deeper level exists
foreach ($subarrays as $subarray) {
deepestArrays($subarray, $level + 1, $lowest); // recurse each subarray
}
} else { // deepest level in branch
$lowestLevel = key($lowest) ?? $level; // if lowest array is empty, key will be null, fallback to $level value
if ($lowestLevel === $level) {
$lowest[$level][] = $array; // push the array into the results
} elseif ($lowestLevel < $level) {
$lowest = [$level => [$array]]; // overwrite with new lowest array
}
}
return current($lowest); // return the deepest array
}
var_export(
deepestArrays($testArray)
);
I need to search a multidimensional array for a specific value in any of the indexed subarrays.
In other words, I need to check a single column of the multidimensional array for a value. If the value exists anywhere in the multidimensional array, I would like to return true otherwise false
$my_array = array(
0 => array(
"name" => "john",
"id" => 4
),
1 => array(
"name" => "mark",
"id" => 152
),
2 => array(
"name" => "Eduard",
"id" => 152
)
);
I would like to know the fastest and most efficient way to check if the array $my_array contains a value with the key "id". For example, if id => 152 anywhere in the multidimensional array, I would like true.
Nothing will be faster than a simple loop. You can mix-and-match some array functions to do it, but they'll just be implemented as a loop too.
function whatever($array, $key, $val) {
foreach ($array as $item)
if (isset($item[$key]) && $item[$key] == $val)
return true;
return false;
}
The simplest way is this:
$my_array = array(
0 => array(
"name" => "john",
"id" => 4
),
1 => array(
"name" => "mark",
"id" => 152
),
2 => array(
"name" => "Eduard",
"id" => 152
)
);
if (array_search(152, array_column($my_array, 'id')) !== FALSE) {
echo 'FOUND!';
} else {
echo 'NOT FOUND!';
}
** PHP >= 5.5
simply u can use this
$key = array_search(40489, array_column($userdb, 'uid'));
Let's suppose this multi dimensional array:
$userdb=Array
(
(0) => Array
(
(uid) => '100',
(name) => 'Sandra Shush',
(url) => 'urlof100'
),
(1) => Array
(
(uid) => '5465',
(name) => 'Stefanie Mcmohn',
(pic_square) => 'urlof100'
),
(2) => Array
(
(uid) => '40489',
(name) => 'Michael',
(pic_square) => 'urlof40489'
)
);
$key = array_search(40489, array_column($userdb, 'uid'));
Here is an updated version of Dan Grossman's answer which will cater for multidimensional arrays (what I was after):
function find_key_value($array, $key, $val)
{
foreach ($array as $item)
{
if (is_array($item) && find_key_value($item, $key, $val)) return true;
if (isset($item[$key]) && $item[$key] == $val) return true;
}
return false;
}
If you have to make a lot of "id" lookups and it should be really fast you should use a second array containing all the "ids" as keys:
$lookup_array=array();
foreach($my_array as $arr){
$lookup_array[$arr['id']]=1;
}
Now you can check for an existing id very fast, for example:
echo (isset($lookup_array[152]))?'yes':'no';
A good solution can be one provided by #Elias Van Ootegan in a comment that is:
$ids = array_column($array, 'id', 'id');
echo isset($ids[40489])?"Exist":"Not Exist";
I tried it and worked for me, thanks buddy.
Edited
Note: It will work in PHP 5.5+
TMTOWTDI. Here are several solutions in order of complexity.
(Short primer on complexity follows):O(n) or "big o" means worst case scenario where n means the number of elements in the array, and o(n) or "little o" means best case scenario. Long discrete math story short, you only really have to worry about the worst case scenario, and make sure it's not n ^ 2 or n!. It's more a measure of change in computing time as n increases than it is overall computing time. Wikipedia has a good article about computational aka time complexity.
If experience has taught me anything, it's that spending too much time optimizing your programs' little-o is a distinct waste of time better spent doing something - anything - better.
Solution 0: O(n) / o(1) complexity:
This solution has a best case scenario of 1 comparison - 1 iteration thru the loop, but only provided the matching value is in position 0 of the array. The worst case scenario is it's not in the array, and thus has to iterate over every element of the array.
foreach ($my_array as $sub_array) {
if (#$sub_array['id'] === 152) {
return true;
}
}
return false;
Solution 1: O(n) / o(n) complexity:
This solution must loop thru the entire array no matter where the matching value is, so it's always going to be n iterations thru the array.
return 0 < count(
array_filter(
$my_array,
function ($a) {
return array_key_exists('id', $a) && $a['id'] == 152;
}
)
);
Solution 2: O(n log n) / o(n log n) complexity:
A hash insertion is where the log n comes from; n hash insertions = n * log n. There's a hash lookup at the end which is another log n but it's not included because that's just how discrete math works.
$existence_hash = [];
foreach ($my_array as $sub_array) {
$existence_hash[$sub_array['id']] = true;
}
return #$existence_hash['152'];
I came upon this post looking to do the same and came up with my own solution I wanted to offer for future visitors of this page (and to see if doing this way presents any problems I had not forseen).
If you want to get a simple true or false output and want to do this with one line of code without a function or a loop you could serialize the array and then use stripos to search for the value:
stripos(serialize($my_array),$needle)
It seems to work for me.
As in your question, which is actually a simple 2-D array wouldn't it be better? Have a look-
Let say your 2-D array name $my_array and value to find is $id
function idExists($needle='', $haystack=array()){
//now go through each internal array
foreach ($haystack as $item) {
if ($item['id']===$needle) {
return true;
}
}
return false;
}
and to call it:
idExists($id, $my_array);
As you can see, it actually only check if any internal index with key_name 'id' only, have your $value. Some other answers here might also result true if key_name 'name' also has $value
I don't know if this is better or worse for performance, but here is an alternative:
$keys = array_map(function($element){return $element['id'];}, $my_array);
$flipped_keys = array_flip($keys);
if(isset($flipped_keys[40489]))
{
// true
}
You can create a queue of sub-arrays and loop each:
function existsKeyValue($myArray, $key, $value) {
$queue = [$myArray]; //creating a queue of a single element, which is our outermost array
//when we reach the count of the queue we looped all inner loops as well and failed to find the item
for ($index = 0; $index < count($queue); $index++) {
//Looping the current array, finding the key and the value
foreach ($queue[$index] as $k => &$v) {
//If they match the search, then we can return true
if (($key === $k) && ($value === $v)) {
return true;
}
//We need to make sure we did not already loop our current array to avoid infinite cycles
if (is_array($v)) $queue[]=$v;
}
}
return false;
}
$my_array = array(
0 => array(
"name" => "john",
"id" => 4
),
1 => array(
"name" => "mark",
"id" => 152
),
2 => array(
"name" => "Eduard",
"id" => 152
)
);
echo var_dump(existsKeyValue($my_array, 'id', 152));
array_column returns the values of a single column of an array and we can search for a specific value for those via in_array
if (in_array(152, array_column($my_array, 'id'))) {
echo 'FOUND!';
} else {
echo 'NOT FOUND!';
}
Try with this below code. It should be working fine for any kind of multidimensional array search.
Here you can see LIVE DEMO EXAMPLE
function multi_array_search($search_for, $search_in) {
foreach ($search_in as $element) {
if ( ($element === $search_for) ){
return true;
}elseif(is_array($element)){
$result = multi_array_search($search_for, $element);
if($result == true)
return true;
}
}
return false;
}
You can use this with only two parameter
function whatever($array, $val) {
foreach ($array as $item)
if (isset($item) && in_array($val,$item))
return 1;
return 0;
}
different between isset vs array_key_exits
What's the difference between isset() and array_key_exists()?
different between == vs === How do the PHP equality (== double equals) and identity (=== triple equals) comparison operators differ?
function specificValue(array $array,$key,$val) {
foreach ($array as $item)
if (array_key_exits($item[$key]) && $item[$key] === $val)
return true;
return false;
}
function checkMultiArrayValue($array) {
global $test;
foreach ($array as $key => $item) {
if(!empty($item) && is_array($item)) {
checkMultiArrayValue($item);
}else {
if($item)
$test[$key] = $item;
}
}
return $test;
}
$multiArray = array(
0 => array(
"country" => "",
"price" => 4,
"discount-price" => 0,
),);
$test = checkMultiArrayValue($multiArray);
echo "<pre>"
print_r($test);
Will return array who have index and value
I wrote the following function in order to determine if an multidimensional array partially contains a certain value.
function findKeyValue ($array, $needle, $value, $found = false){
foreach ($array as $key => $item){
// Navigate through the array completely.
if (is_array($item)){
$found = $this->findKeyValue($item, $needle, $value, $found);
}
// If the item is a node, verify if the value of the node contains
// the given search parameter. E.G.: 'value' <=> 'This contains the value'
if ( ! empty($key) && $key == $needle && strpos($item, $value) !== false){
return true;
}
}
return $found;
}
Call the function like this:
$this->findKeyValue($array, $key, $value);