search words in two arrays - php

I am trying to search two arrays and return the index of matching words that match in array 1 from array 2. following are the arrays:
$array1 = array('hello how are you', 'hello I am fine');
$array2 = array('hello','how');
I am trying the following code and it return 0,1 which is fine. But i only want to return 0. I want it to return only where both words are present in the array.
foreach ($array1 as $reference => $array) {
foreach($array2 as $key => $word) {
if(strpos($array, $word) !== false) {
echo $reference, PHP_EOL;
break;
}
}
}

You need to keep track of each entity from $array2 being checked against each entity from $array1 then compare after the inner loop to decide whether all elements from $array2 are present in $array1. Here's an example:
foreach($array1 as $reference => $array) {
$contains = 0;
foreach($array2 as $key => $word) {
if(strpos($array, $word) !== false) {
$contains++;
} else {
// for performance reasons, e.g. if you have a large array,
// you should break the loop here if the word isn't in the
// original array
break;
}
}
if($contains == count($array2)) {
// $array contains all words from $array2
echo $reference . PHP_EOL;
} else {
// $array doesn't contain all the words
}
}

Related

Using array_keys to search a multidimensional array with a partial array

$testArray = array(
array(1,2,"file1.png"),
array(1,3,"file2.png"),
array(1,4,"file3.png")
);
print_r (array_keys($testArray, array(1,3, "file2.png"))); // Works
print_r (array_keys($testArray, array(1,3))); // Does not work.
As shown in the code above, I'd like to be able to quickly find an array in a multidimensional array but only specify two of the values.
One way to do this is to filter the testArray down to those number of keys using array_map, then use array_search to get the key.
$testArray = array(
array(1,2,"file1.png"),
array(1,3,"file2.png"),
array(1,4,"file3.png")
);
$search = [1,3];
$filtered = array_map(function ($item) use ($search){
return array_slice($item, 0, count($search));
}, $testArray);
$key = array_search($search, $filtered);
if ($key !== false){
print_r($testArray[$key]);
} else {
echo 'not found';
}
You can filter the array by testing which ones contain the values by computing the intersection and then get those keys:
$keys = array_keys(array_filter($testArray,
function($v) {
return count(array_intersect([1,3], $v)) == 2;
}));
You can extend it with a search $s variable:
$s = [1,3];
$keys = array_keys(array_filter($testArray,
function($v) use($s) {
return count(array_intersect($s, $v)) == count($s);
}));
This will return the keys for any sub array that contains [1,3], [3,1] or even [3,"file2.png",1], order is irrelevant.
To check them in order:
$s = [1,3];
$keys = array_keys(array_filter($testArray,
function($v) use($s) {
return count(array_intersect_assoc($s, $v)) == count($s);
}));
Loop through your data and slice each triplet, taking the first two items, and compare these to your needle. Return the file given a match.
<?php
$data = array(
array(1, 2, "file1.png"),
array(1, 3, "file2.png"),
array(1, 4, "file3.png")
);
$get_file_from_coords = function(array $coords) use ($data) {
foreach($data as $v) {
if (array_slice($v, 0, 2) == $coords) {
return $v[2];
}
}
};
echo $get_file_from_coords([1, 3]);
Output:
file2.png
(Note: If you have more than one file associated with your co-ordinate pair you'll need to adapt the code to return an array of matches.)
You don't necessarily need to slice or do anything fancy here. You can just compare like so:
[$v[0], $v[1]] == $coords
Your array data
$testArray = [
[1, 2, 'file1.png'],
[1 ,3, 'file2.png'],
[1 ,4, 'file3.png']
];
Specify what your search match conditions into an array
$matching = [1, 3];
Loop through your array data to find matches using array_intersect_assoc() which compares values and keys between two arrays. Store the actual found key and its values into a new array.
foreach ($testArray as $index => $contents) {
if (array_intersect_assoc($matching, $contents) == $matching) {
$found[$index] = $contents;
}
}
Display the results
echo '<pre>';
!empty($found) ? print_r($found) : print_r('not found');

remove value from array what the words is not fully match

How i can remove a value from array what is not fully match the letters.
Array code example:
$Array = array(
'Funny',
'funnY',
'Games',
);
How I can unset all values from this array what is 'funny'
I try via unset('funny'); but is not removing the values from array, is removed just if i have 'funny' on array but 'funnY' or 'Funny' not working
Maybe there is some sophisticated solution with array_intersect_key or something which could do this in one line but I assume this approach is more easily read:
function removeCaseInsensitive($array, $toRemove) {
$ret = [];
foreach ($array as $v) {
if (strtolower($v) != strtolower($toRemove))
$ret[] = $v;
}
return $ret;
}
This returns a new array that does not contain any case of $toRemove. If you want to keep the keys than you can do this:
function removeCaseInsensitive($array, $toRemove) {
$keep = [];
foreach ($array as $k => $v) {
if (strtolower($v) != strtolower($toRemove))
$keep[$k] = true;
}
return array_intersect_keys($array, $keep);
}
You can filter out those values with a loose filtering rule:
$array = array_filter($array, function($value) {
return strtolower($value) !== 'funny';
});

How To get sub array keys from array by less than values

I want to get sub array keys from array by less than values.
This is an example:
$arr_less_than = array(55,60,10,70);
$BlackList = array(10,8,15,20);
$MasterArray = array(
10 => array(1 => array(50,20,5,40), 2 => array(70,77,58,10), 3 => array(155,95,110,105), 4 => array(250,215,248,188)),
11 => array(1 => array(5,65,49,100), 2 => array(80,85,60,30), 3 => array(175,85,95,120), 4 => array(235,205,218,284)),
12 => array(1 => array(82,80,55,80), 2 => array(90,90,74,110), 3 => array(180,122,156,222), 4 => array(255,225,233,263)),
13 => array(1 => array(350,360,400,375), 2 => array(95,99,111,75), 3 => array(188,112,66,111), 4 => array(66,69,33,110)),
);
Now I need to get sub array keys from $MasterArray by less than $arr_less_than if the sub array key is not in the array $BlackList.
For the above example, the result must return array(12,13).
Note: I don't want to use a foreach loop
There are 2 solutions here - one for all sub-arrays meet the criteria, and one for any sub-array meets the criteria (which it seems is what the OP had in mind). At the end, there are foreach based solutions for the latter case where ANY sub-array meets the criteria.
If I understand the problem correctly, the goal is to identify rows in MasterArray where all of the sub-arrays have values that are greater than the corresponding value in $arr_less_than.
The OP does not want to use foreach (See the end of the answer for foreach based answers which are much simpler) - which may actually produce a more efficient version because it can avoid unnecessary compares and save some cycles, so here is a heavily annotated version using array functions.
I've excluded the data which can be copied from OP's post:
function getMatchingRows($arr_less_than, $MasterArray, $BlackList)
{
return array_values( // When we're done we just want a straight array of the keys from $MasterArray
array_filter(
array_keys($MasterArray), // Iterate over $MasterArray's keys (Because we need the keys for the BlackList)
function ($v) use ($BlackList, $MasterArray, $arr_less_than) {
// Filter out MasterArray Entries that dont meet the criteria
echo "Evaluate $MasterArray[$v]" . PHP_EOL;
// Remove array entries whose key is in the BlackList
if (in_array($v, $BlackList)) {
echo "\tBlacklisted" . PHP_EOL;
return false;
}
// For each entry in the MasterArray value, add up the number of non-matching entries
$y = array_reduce(
$MasterArray[$v],
function ($c1, $sub) use ($arr_less_than) {
// For each subarray entry in a MasterArray value, reduce the array to a count
// of elements whose value is less than the corresponding value in the $arr_less_than
$s1 = array_reduce(
array_keys($sub),
function ($carry, $key) use ($sub, $arr_less_than) {
if ($sub[$key] <= $arr_less_than[$key]) {
return ++$carry;
}
},
0 // Initial value for the array_reduce method
);
// $s1 will be a count of non-matching values
return $c1 + $s1;
},
0 //Initial value for the array_reduce method
);
echo "\t$y" . PHP_EOL;
// Include the array value in the filter only if there are no non-matching values ($y == 0)
return !$y;
}
)
);
}
print_r(getMatchingRows($arr_less_than, $MasterArray, $BlackList));
The basic idea is to generate a list of keys from the outermost array - so we iterate over them with array_filter. Then we exclude those with a key in the blacklist. Rows that arent in the blacklist, are reduced into an integer by iterating over each sub=arrays values and comparing them positon-wise against $arr_less_than and adding 1 for each value that fails to be greater than the corresponding member in $arr_less_than. Then those values are summed for all of the members in the MasterArray row. If the result is zero, then the row passes. Finally, the ultimate result is passed to array_values to normalize the resulting array.
Note that this requires that all values be compared, even if the first sub-value in the first sub-array fails. For that reason a foreach approach that can escape may be more efficient.
This is essentially the same method without comments and couple of shortcuts:
function getMatchingRows($arr_less_than, $MasterArray, $BlackList)
{
return array_values( // When we're done we just want a straight array of the keys from $MasterArray
array_filter(
array_keys($MasterArray),
function ($v) use ($BlackList, $MasterArray, $arr_less_than) {
return !in_array($v, $BlackList) && !array_reduce(
$MasterArray[$v],
function ($c1, $sub) use ($arr_less_than) {
return $c1 ?: array_reduce(
array_keys($sub),
function ($carry, $key) use ($sub, $arr_less_than) {
return $carry ?: ($sub[$key] <= $arr_less_than[$key] ? 1 : 0);
},
0
);
},
0
);
}
)
);
}
Some of the methods in array_reduce are short-circuited using ?: operator since the actual count is irrelevant. Once the count exceeds zero, the row fails, regardless.
Here is similar code if the criterion is that AT LEAST ONE sub-array has all members greater than the reference array.
function getMatchingRowsAny($arr_less_than, $MasterArray, $BlackList)
{
return array_values( // When we're done we just want a straight array of the keys from $MasterArray
array_filter(
array_keys($MasterArray), // Iterate over $MastrArray's keys (Because we need the keys for theBlackList)
function ($v) use ($BlackList, $MasterArray, $arr_less_than) {
// Filter out MasterArray Entries that dont meet the criteria
echo "Evaluate \MasterArray[$v]" . PHP_EOL;
// Remove array entries whose key is in the BlackList
if (in_array($v, $BlackList)) {
echo "\tBlacklisted" . PHP_EOL;
return false;
}
// For each entry in the MasterArray value, add up the number of non-matching entries
$y = array_reduce(
$MasterArray[$v],
function ($c1, $sub) use ($arr_less_than) {
// For each subarray entry in a MasterArray value, reduce the array to a flag
// indicating if it has whose value is <= the corresponding value in the $arr_less_than
$s1 = array_reduce(
array_keys($sub),
function ($fail, $key) use ($sub, $arr_less_than) {
return $fail || $sub[$key] <= $arr_less_than[$key];
},
false
);
// This could be short-circuited above to avoid an unnecessary array_reduce call
return $c1 || !$s1;
},
false
);
echo "\t$y" . PHP_EOL;
// Include the array value in the filter if there are any matching values
return $y;
}
)
);
}
print_r(getMatchingRowsAny($arr_less_than, $MasterArray, $BlackList));
As an exercise (and because I'm a glutton for punishment) I rendered the same methods using foreach as both a generator and a function returning an array - mostly to illustrate that foreach may be the better choice, and is definitely simpler:
// Implemented as a generator - The associated foreach that uses it follows
function generateMatchingRows($arr_less_than, $MasterArray, $BlackList)
{
foreach ($MasterArray as $k => $v) {
if (in_array($k, $BlackList)) {
continue;
}
foreach ($v as $sub_array) {
$match = true;
foreach ($sub_array as $k1 => $v1) {
if ($v1 <= $arr_less_than[$k1]) {
$match = false;
break;
}
}
if ($match) {
yield $k;
break;
}
}
}
}
foreach (generateMatchingRows($arr_less_than, $MasterArray, $BlackList) as $k) {
echo $k . PHP_EOL; // Or push them onto an array
}
// Implemented as a function returning an array - classical approach - just return an array
function getMatchingRowsForEach($arr_less_than, $MasterArray, $BlackList)
{
$rv = [];
foreach ($MasterArray as $k => $v) {
if (in_array($k, $BlackList)) {
continue;
}
foreach ($v as $sub_array) {
$match = true;
foreach ($sub_array as $k1 => $v1) {
if ($v1 <= $arr_less_than[$k1]) {
$match = false;
break;
}
}
if ($match) {
$rv[] = $k;
break;
}
}
}
return $rv;
}
print_r(getMatchingRowsForEach($arr_less_than, $MasterArray, $BlackList));

Check if array element already partially exists inside of the array

I have an array that looks like this:
[Amsterdam, Elderly people, Thousand students, Sixteen thousand students, Clean houses]
As you can see, there's an entry "thousand students" and an entry "sixteen thousand students". Is there a way that would let me filter out thousand students (and delete this entry), since it already partially exists?
However, just unsetting the element by hand won't work. The array is the result of an API, which means I won't know if there are partial duplicates or not.
thanks.
Edit: Expected result:
[Amsterdam, Elderly people, Sixteen thousand students, Clean houses]
So I'm trying to work out a slicker way without two loops, but this will do it:
foreach($array as $k => $a) {
foreach($array as $b) {
if(strtolower($a) !== strtolower($b) &&
(strpos(strtolower($b), strtolower($a)) !== false)) {
unset($array[$k]);
}
}
}
Loop the array and compare each value in lower case to each other value in lower case
If they are not equal and one is found within the other, use the key to remove the one found in the other
Maybe a little shorter:
foreach(array_map('strtolower', $array) as $k => $a) {
foreach(array_map('strtolower', $array) as $b) {
if($a !== $b && (strpos($b, $a) !== false)) {
unset($array[$k]);
}
}
}
Try this:
<?php
function custom_filter( $data ) {
$data_lc = array_map(function($value){
return strtolower($value);
}, $data);
foreach ($data_lc as $keyA => $valueA) {
foreach ($data_lc as $keyB => $valueB) {
if ( $keyA === $keyB ) {
continue;
}
if ( false !== strpos($valueA, $valueB) ) {
if ( strlen($valueA) <= strlen($valueB) ) {
unset($data[$keyA]);
} else {
unset($data[$keyB]);
}
}
}
}
return $data;
}
$array = ['Amsterdam', 'Elderly people', 'Thousand students', 'Sixteen thousand students', 'Clean houses'];
print_r( custom_filter( $array ) );
This should do the trick, however it'll only look for matches at the word level, and it's case sensitive.
<?php
$wordsList = [
'Amsterdam', 'Elderly people', 'Thousand students',
'Sixteen thousand students', 'Clean houses',
];
$lookup = array();
foreach ($wordsList as $k => $words) {
$phrase = '';
foreach (preg_split('`\s+`', $words, -1, PREG_SPLIT_NO_EMPTY) as $word) {
$phrase .= $word;
if (in_array($phrase, $words)) {
unset($wordsList[$k]);
break;
}
}
}

how can I get my php array data to persist?

When I query the data within the foreach loop it works, but makes a duplicate for each pass in the loop. I try to var_dump it anywhere else outside the loop and the data isn't there. Why won't my data persist outside the forEach loop?
<?php
$old_array = [10-2, 13=>"3452", 4=>"Green",
5=>"Green", 6=>"Blue", "green"=>"green",
"two"=>"green" ,"2"=>"green" , "rulebreak" =>"GrEeN",
"ninja"=>" Green ", ["blue" => "green", "green"=>"green", 2 => "itsGreen"] ];
$newArray = array();
function filter_Green($array) {
$find = "green";
$replace = "not green";
/* Same result as using str_replace on an array, but does so recursively for multi-dimensional arrays */
/* found here:
if (!is_array($array)) {
/* Used ireplace so that searches can be case insensitive */
return str_ireplace($find, $replace, $array);
}
foreach ($array as $key => $value) {
$newArray[$key] = $value;
if ($key == "green") {
$newArray[$key] = "not green";
}
if ($value == "green") {
$newArray[$value] = "not green";
}
}
return $newArray;
}
filter_Green($old_array);
var_dump($newArray);
?>
Expectation: When I run the function it should replace all instances of "green" with "not green" and save those into a $newArray. I have it returning $newArray but even then it doesn't seem to match up that the values are being saved into the newArray, hence why I'm doing var_dump to check if it's even working (it appears to not be)
Results: as it is setup, I get an empty array returned to me...It seems to work somewhat if I move var_dump($newArray) to within the foreach loop but that then duplicates the data for each pass.
if you want var_dump $newArray out side the function then you should declare $newArray as global in your function
<?php
$old_array = [10-2, 13=>"3452", 4=>"Green", 5=>"Green", 6=>"Blue", "green"=>"green", "two"=>"green" ,"2"=>"green" , "rulebreak" =>"GrEeN", "ninja"=>" Green ", ["blue" => "green", "green"=>"green", 2 => "itsGreen"] ];
$newArray = array();
function filter_Green($array) {
global $newArray;
$find = "green";
$replace = "not green";
/* Same result as using str_replace on an array, but does so recursively for multi-dimensional arrays */
if (!is_array($array)) {
/* Used ireplace so that searches can be case insensitive */
return str_ireplace($find, $replace, $array);
}
foreach ($array as $key => $value) {
$newArray[$key] = $value;
if ($key == "green") {
$newArray[$key] = "not green";
}
if ($value == "green") {
$newArray[$value] = "not green";
}
}
return $newArray;
}
filter_Green($old_array);
var_dump($newArray);
?>
But instead of declaring global in function, use returned value by filter_Green($old_array); as below
$result = filter_Green($old_array);
var_dump($result);

Categories