php array_intersect associative and indexed array - php

How can I check if keys are set in an array without using multiple isset(...)
I thought of something like:
$arr1 = [
"keyA" => 1,
"keyB" => 2,
"keyC" => 3
];
$arr2 = ['keyB', 'keyD'];
$anyExists = empty(array_intersect($arr1, $arr2));
This should evaluate to true if any item of $arr2 is a key of $arr1.
It obviously does not work. But is there a similarly nice solution without using loops?

So you want to get the keys as values from the first array as it checks values and not keys, and you want !empty() to return true if it's NOT empty and false if it IS empty:
$anyExists = !empty(array_intersect(array_keys($arr1), $arr2));
You could use array_intersect_key(), but then you would need to flip the second array to get the values as keys:
$anyExists = !empty(array_intersect_key($arr1, array_flip($arr2)));
Or define your array as:
$arr2 = ['keyB' => true, 'keyD' => true];

I find disallowing multiple isset() calls to be an unfortunate requirement because it is sure to be the faster option. Additionally, by writing the calls into a loop with a conditional break or return will improve its efficiency again.
Code: (Demo)
function anyKeyExists($haystack, $needles) {
foreach ($needles as $needle) {
if (isset($haystack[$needle])) {
return true;
}
}
return false;
}
$array = [
"keyA" => 1,
"keyB" => 2,
"keyC" => 3
];
echo "noMatch: " , (int)anyKeyExists($array, ['keyD', 'keyF']) , "\n";
echo "oneMatch: " , anyKeyExists($array, ['keyB', 'keyD']) , "\n";
echo "twoMatches: " , anyKeyExists($array, ['keyA', 'keyC']) , "\n";
Output:
noMatch: 0
oneMatch: 1
twoMatches: 1
If you must use functional programming, you can avoid the empty() call after intersecting the keys by merely casting the output array as a boolean using !! or (bool).
Code: (Demo)
$array = [
"keyA" => 1,
"keyB" => 2,
"keyC" => 3
];
echo "noMatch: " , (int)!!array_intersect_key($array, array_flip(['keyD', 'keyF'])) , "\n";
echo "oneMatch: " , !!array_intersect_key($array, array_flip( ['keyB', 'keyD'])) , "\n";
echo "twoMatches: " , !!array_intersect_key($array, array_flip(['keyA', 'keyC'])) , "\n";
(Same output as previous snippet)
P.s. It should be obvious, but in case it is not, I'll explain that my techniques are returning true or false evaluations. I am casting the false outcomes as (int) so that they are expressed as 0 values instead of empty strings. true, when echoed, is represented as a 1.

Related

Multiple values in array excluding specified key [duplicate]

This question already has answers here:
Deleting an element from an array in PHP
(25 answers)
Closed 9 months ago.
I'm trying to verify if certain values exist within an array excluding a specific key:
$haystack = array(
"id" => 1,
"char1" => 2,
"char2" => 3,
"char3" => 4,
);
$needles = array(2, 4);
Solution that I found here: in_array multiple values
function in_array_all($needles, $haystack) {
return empty(array_diff($needles, $haystack));
}
The problem is that I'm checking if certain chars exist within the array. This will work fine in this case:
$exists = in_array_all([2, 4], $haystack); // true
But it'll cause an issue in this situation:
$exists = in_array_all([1, 3], $haystack); // true
It found the value 1 in the key id and therefor evaluates as true while a char with id 1 is not within the array. How can I make it so that it excludes the key id within the search?
Note: This is example data. The real data is much larger, so just using if / else statements isn't really viable.
function in_array_all($needles, $haystack) {
return empty(array_diff($needles, $haystack));
}
function excludeKeys($haystack){
$tempArray = array();
foreach($haystack as $key => $value){
if ($key == "id"){
// Don't include
}else{
$tempArray[$key] = $value;
}
}
return $tempArray;
}
$haystack = array(
"id" => 1,
"char1" => 2,
"char2" => 3,
"char3" => 4,
);
$exists = in_array_all([1, 3], excludeKeys($haystack));
echo("Exists: ".($exists ? "Yes" : "No"));
This basically just returns the array without the keys you specify. This keeps the original array in tact for later use.
Edit:
These bad solutions are really a symptom of a problem in your data structure. You should consider converting your array to an object. It looks like this:
$object = new stdClass();
$object->id = 1;
$object->chars = array(2, 3, 4);
$exists = in_array_all([1, 3], $object->chars);
This is how you're supposed to separate your data up. This way you can properly store your information by key. Furthermore you can store other objects or arrays within the object specific to a key, as shown above.
Unset id index and then do search:
function in_array_any($needles, $haystack) {
unset($haystack['id']);
return !array_diff($needles, $haystack);
}
https://3v4l.org/PTjOS

How to compare arrays and get matching data

I have an array $data, that looks something like this:
[
1 => "1234,10-12-2022",
2 => "1356,01-02-2021",
3 => "1677,03-05-2020",
];
Then, I have another array $search that looks like this: ['1234','1677']
I can get results of any of those items in $data by date,but once I have a match, i need to check if there is a match from another array, and get that date[1] and value[0] as output. Also it is possible that in match all 3 values[0] are present.
How I can find most recent matches of it?
This is what I have tried:
`$f = array_values(array_intersect(array_map(
function($item){
return explode(',', $item)[0];
},
$c), $p));
var_dump($f);//finds match
if($f){
//pass this to find date-time but I need most recent one for //every value
$c = get_comment_meta($user_id,'value');
$new_to_old = array_reverse($c);
$newArr = array();
foreach ( $new_to_old as $x ) {
$all_course_meta = explode(",", $x);
array_push ( $newArr, $all_course_meta[0] );
}
$uniqueArr = array_unique($newArr);
$result = array_intersect($uniqueArr, $f);}
var_dump($result);//doeas not returns anything here.`
I have tried various loops and array intersect, diff and etc, but without success.
I'm not sure if I understand your question here, but if you want to compare the first part of the values in the $data with the values in the $search then I think it's will be like this
$a = ['1234,10-12-2022', '1356,01-02-2021', '1677,03-05-2020'];
$b = ['1234', '1677'];
array_values(array_intersect(array_map(function($item){ return explode(',', $item)[0]; }, $a), $b));
the output should be
=> [
"1234",
"1677",
]
I hope it's helpful

Check if two arrays are equal key value with same name

I have two arrays:
$arr1 = array(
1 => 250,
2 => 325,
3 => 741,
4 => 690
);
$arr2 = array(
1 => 110,
2 => 740,
3 => 1200,
4 => 500
);
I want to check if all $arr2 values are less than $arr1 values
There are now 2 keys [1] + [4] its less than $arr1 keys [1] + [4]
Without a foreach loop, I want to return true or false if any key from $arr2 is less than the same key from $arr1.
Here is one way to do it.
$result = (bool) array_filter(array_map(function($a, $b){
return $b < $a;
}, $arr1, $arr2));
The inner array_map returns true or false based on the comparison of corresponding values of $arr1 and $arr2. Then the outer array_filter reduces the result to only include true values. Casting the result to boolean will yield true if all values in $arr2 are greater than or equal to the corresponding $arr1 values (because array_filter will return an empty array), and false if any of them are less.
Keep in mind that avoiding a foreach loop is not more efficient for something like this. Both the array_map and array_filter functions will iterate the entire array they are given. If you use a foreach instead, you can break out of the loop as soon as you find an element that meets the condition you're looking for, which in this case would be the first iteration of the foreach loop.
Here is an example that does not use foreach() but most of us would use an iterator to work with array elements. You could use for() or while() loops, too.
<?php // demo/temp_samer.php
/**
* Compare array elements
*
* https://stackoverflow.com/questions/45422576/check-if-two-arrays-are-equal-key-value-with-same-name
*/
error_reporting(E_ALL);
echo '<pre>';
$arr1=array('1'=>250,'2'=>325,'3'=>741,'4'=>690);
$arr2=array('1'=>110,'2'=>740,'3'=>1200,'4'=>500);
if ($arr2[1] < $arr1[1]) echo PHP_EOL . "KEY 1 IS LOWER IN THE SECOND ARRAY";
if ($arr2[2] < $arr1[2]) echo PHP_EOL . "KEY 2 IS LOWER IN THE SECOND ARRAY";
if ($arr2[3] < $arr1[3]) echo PHP_EOL . "KEY 3 IS LOWER IN THE SECOND ARRAY";
if ($arr2[4] < $arr1[4]) echo PHP_EOL . "KEY 4 IS LOWER IN THE SECOND ARRAY";
This shows a way of thinking about the problem.
https://iconoun.com/demo/temp_samer.php
<?php // demo/temp_samer.php
/**
* Compare array elements
*
* https://stackoverflow.com/questions/45422576/check-if-two-arrays-are-equal-key-value-with-same-name
*/
error_reporting(E_ALL);
echo '<pre>';
$arr1=array('1'=>250,'2'=>325,'3'=>741,'4'=>690);
$arr2=array('1'=>110,'2'=>740,'3'=>1200,'4'=>500);
foreach ($arr2 as $key => $value)
{
if ($value < $arr1[$key]) echo PHP_EOL . "KEY $key IS LOWER IN THE SECOND ARRAY";
}

How to extract array values with numeric keys only?

Considering array like:
$arr = array(
'key' => 'foo'
'key2' => 'bar',
0 => 'num_foo',
1 => 'num_bar'
);
How to extract values under 0 & 1? (Besides using for loop). Maybe any standard function do the job?
If you’re using a PHP version >= 5.6, you can use array_filter, with the flag that tells it to pass the key to the callback function.
$arr = array(
'key' => 'foo',
'key2' => 'bar',
0 => 'num_foo',
1 => 'num_bar'
);
$new_array = array_filter($arr, function($key) {
return is_numeric($key);
}, ARRAY_FILTER_USE_KEY);
var_dump($new_array);
https://3v4l.org/qfar9
Edit: As Robbie pointed out, using is_numeric is the better choice here. (Previously my example used is_int.)
Edit 2: Perhaps is_int is actually the better choice here. is_numeric would return true for values such as +0123.45e6, or hexadecimal/binary number notations as well – not sure if that’s desired.
is_int would normally return false for a value such as '1'. It works here, because we are dealing with arrays – and PHP automatically converts array keys to integer, if they are an “integer string.”
you can use array_filter() to return the numeric keys
// $Your_array is your original array with numeric and string keys
// array_filter() returns an array of the numeric keys
$numerickeys = array_filter(array_keys($Your_array), function($k) {return is_int($k);});
// this is a simple case where the filter function is a plain
// built-in function requiring one argument, it can be passed as a string:
// Really, this is all that's needed:
$numerickeys = array_filter(array_keys($Your_array), 'is_int');
If you use is_int() inside a foreach loop it's easy enough. Try this:
foreach ($arr as $key => $value) {
if (is_int($key)) {
echo "Found integer key with value: $value\n";
}
}
If you desperately want to avoid using a loop, try this:
array_walk($arr, function($val, $key) {
if (is_int($key)) {
echo "Found integer key with value: $val\n";
}
});
That does, of course, use a loop internally anyway.

php - get numeric index of associative array

I have an associative array and I need to find the numeric position of a key.
I could loop through the array manually to find it, but is there a better way build into PHP?
$a = array(
'blue' => 'nice',
'car' => 'fast',
'number' => 'none'
);
// echo (find numeric index of $a['car']); // output: 1
echo array_search("car",array_keys($a));
$blue_keys = array_search("blue", array_keys($a));
http://php.net/manual/en/function.array-keys.php
While Fosco's answer is not wrong there is a case to be considered with this one: mixed arrays. Imagine I have an array like this:
$a = array(
"nice",
"car" => "fast",
"none"
);
Now, PHP allows this kind of syntax but it has one problem: if I run Fosco's code I get 0 which is wrong for me, but why this happens?
Because when doing comparisons between strings and integers PHP converts strings to integers (and this is kinda stupid in my opinion), so when array_search() searches for the index it stops at the first one because apparently ("car" == 0) is true.
Setting array_search() to strict mode won't solve the problem because then array_search("0", array_keys($a)) would return false even if an element with index 0 exists.
So my solution just converts all indexes from array_keys() to strings and then compares them correctly:
echo array_search("car", array_map("strval", array_keys($a)));
Prints 1, which is correct.
EDIT:
As Shaun pointed out in the comment below, the same thing applies to the index value, if you happen to search for an int index like this:
$a = array(
"foo" => "bar",
"nice",
"car" => "fast",
"none"
);
$ind = 0;
echo array_search($ind, array_map("strval", array_keys($a)));
You will always get 0, which is wrong, so the solution would be to cast the index (if you use a variable) to a string like this:
$ind = 0;
echo array_search((string)$ind, array_map("strval", array_keys($a)));
The solution with array_search would be really heavy, and it's unnecessary to use straight search in this situation.
Much better solution would be:
$keyIndexOfWhichYouAreTryingToFind = 'c';
$array = [
'a' => 'b',
'c' => 'd'
];
$index = array_flip(array_keys($array))[$keyIndexOfWhichYouAreTryingToFind];
This type of search would have much better performance on big arrays.
$a = array(
'blue' => 'nice',
'car' => 'fast',
'number' => 'none'
);
var_dump(array_search('car', array_keys($a)));
var_dump(array_search('blue', array_keys($a)));
var_dump(array_search('number', array_keys($a)));
All solutions based on array_keys don't work for mixed arrays. Solution is simple:
echo array_search($needle,array_keys($haystack), true);
From php.net:
If the third parameter strict is set to TRUE then the array_search() function will search for identical elements in the haystack. This means it will also perform a strict type comparison of the needle in the haystack, and objects must be the same instance.
a solution i came up with... probably pretty inefficient in comparison tho Fosco's solution:
protected function getFirstPosition(array$array, $content, $key = true) {
$index = 0;
if ($key) {
foreach ($array as $key => $value) {
if ($key == $content) {
return $index;
}
$index++;
}
} else {
foreach ($array as $key => $value) {
if ($value == $content) {
return $index;
}
$index++;
}
}
}

Categories