This question already has answers here:
Multiple array_filter and strpos
(4 answers)
Closed 3 years ago.
What I'm trying to do is take items from one array, such as:
$array1 = array(
"google-com",
"youtube-com",
);
And remove items from a second array if the above items are included (but BROAD match, not exact).
$array2 = array(
"www-google-com",
"www-youtube-com",
"www-facebook-com",
"www-twitter-com",
);
Expected output:
www-facebook-com
www-twitter-com
Note: The first array would be with "example.com" style URLs and the second with "https://www.example.com/" URLs.
It seems array_diff only works with exact matches, and after much searching, I can't seem to find a way to make it work for broad matches.
Thanks for your help!
The simplest way to do this is to iterate over each of the arrays, using a function such as strpos to see if the short URLs are contained in the longer ones:
$output = array();
foreach ($array2 as $url) {
$found = false;
foreach ($array1 as $short_url) {
$found = $found || (strpos($url, $short_url) !== false);
}
if (!$found) {
$output[] = $url;
}
}
print_r($output);
Output:
Array
(
[0] => www-facebook-com
[1] => www-twitter-com
)
Without knowing exactly what you mean by a BROAD match, strpos is probably close. You can always write a custom function to do the matching and replace strpos in the code above with it.
When making iterated searches, always provide an early exit.
Nested loops with early break conditions will be most performant.
Code: (Demo)
$array1 = array(
"google-com",
"youtube-com",
);
$array2 = array(
"www-google-com",
"www-youtube-com",
"www-facebook-com",
"www-twitter-com",
);
foreach ($array2 as $index => $haystack) {
foreach ($array1 as $needle) {
if (strpos($haystack, $needle) !== false) {
unset($array2[$index]);
break;
}
}
}
var_export(array_values($array2));
That said, if your data is somewhat predictable and you can prepare just one of the arrays, you can spare much of this iterated work.
You're right, array_diff is not a solution here. One of the solutions is using a preg_grep to find records and then unset keys in $array2:
$array1 = array(
"google-com",
"youtube-com",
);
$array2 = array(
"www-google-com",
"www-youtube-com",
"www-facebook-com",
"www-twitter-com",
);
foreach ($array1 as $search) {
foreach (preg_grep('/' . $search . '/', $array2) as $index => $value) {
unset($array2[$index]);
}
}
print_r($array2);
Hope this resolves your answer to the question :)
$array1 = array(
"google-com",
"youtube-com",
);
$array1 = preg_filter('/^/', 'www-', $array1);
$array2 = array(
"www-google-com",
"www-youtube-com",
"www-facebook-com",
"www-twitter-com",
);
print_r(array_diff($array2, $array1));
Related
I need to remove values from an array that occur more than one time in the array.
For example:
$value = array(10,10,5,8);
I need this result:
$value = array(5,8);
Is there any in-built function in php?
I tried this, but this will not return my expected result:
$unique = array_unique($value);
$dupes = array_diff_key($value, $unique);
You can use array functions and ditch the foreach loops if you wish:
Here is a one-liner:
Code:
$value = [10, 10, 5, 8];
var_export(array_keys(array_intersect(array_count_values($value),[1])));
As multi-line:
var_export(
array_keys(
array_intersect(
array_count_values($value),
[1]
)
)
);
Output:
array (
0 => 5,
1 => 8,
)
This gets the value counts as an array, then uses array_intersect() to only retain values that occur once, then turns the keys into the values of a zero-index array.
The above snippet works identically to #modsfabio's and #axiac's answers. The ONLY advantage in my snippet is brevity. It is possible that their solutions may outperform mine, but judging speed on relatively small data sets may be a waste of dev time. For anyone processing relatively large data sets, do your own benchmarking to find the technique that works best.
For lowest computational/time complexity, use a single loop and as you iterate conditionally populate a lookup array and unset() as needed.
Code: (Demo) (Crosslink to my CodeReview answer)
$values = [10, 10, 5, 8];
$found = [];
foreach ($values as $index => $value) {
if (!isset($found[$value])) {
$found[$value] = $index;
} else {
unset($values[$index], $values[$found[$value]]);
}
}
var_export($values);
// [2 => 5, 3 => 8]
A couple of notes:
If processing float values, using a technique that stores the values as keys (as all of my snippets do), then the results may be incorrect because php will change floats to integers when used as keys.
PHP is consistently much faster at searching for keys than it is at searching for values.
You can do it like this using array_count_values() and a foreach loop:
<?php
$input = array(10,10,5,8);
$output = array();
foreach(array_count_values($input) as $value => $count)
{
if($count == 1)
{
$output[] = $value;
}
}
var_dump($output);
Output:
array(2) {
[0]=>
int(5)
[1]=>
int(8)
}
Example: https://eval.in/819461
A possible approach:
$value = array(10,10,5,8);
$output = array_keys(
array_filter(
array_count_values($value),
function ($count) {
return $count == 1;
}
)
)
array_count_values() produces an array that associates to each unique value from $value the number of times it appears in the array.
array_filter() keeps in this result only the entries (the keys) that appear only once in the original array.
array_keys() produces the desired result.
I would use array_count_values to get an array with how often every element occurs in the array. Then remove all the elements from the original array that occur more than once.
You need to use array_count_values(), array_search() and unset() functions.
<?php
$value = array(10,10,5,8);
echo '<pre>';print_r($value);echo '</pre>';
$cnt = array_count_values($value);
$dup = array();
foreach ($cnt as $k => $repeated) {
if ($repeated > 1) {
if(($key = array_search($k, $value)) !== false) {
unset($value[$key]);
}
}
}
echo '<pre>';print_r($cnt);echo '</pre>';
echo '<pre>';print_r($value);echo '</pre>';
?>
Demo
you can use
foreach loop
and
array_diff() function:
$value=array(10,10,5,8);
$duplicated=array();
foreach($value as $k=>$v)
{
if($kt=array_search($v,$value))!==false and
$k!=$kt)
{if (count(array_keys($array, $value)) > 1)
{
/* Execute code */
}
unset($value[$kt];$duplicated[]=$v;
}
}
$result=array_diff($values,$duplicated);
print_r($result);
output
Array([2]=>5[3]=>8)
I have an array of numeric subarrays. I want to sort all the subarrays, and then sort the whole array, and remove duplicates. Using sort($val) doesn't work, so I found the following workaround with $derp, which I find insanely stupid:
$arr = array( array(5,6), array(1,2), array(6,5) );
foreach ($arr as $key => $val) {
$derp = $val;
sort($derp);
$arr[$key] = $derp;
}
sort($arr);
$arr = array_map("unserialize", array_unique(array_map("serialize", $arr)));
The result is array( array(1,2), array(5,6) ). Is that is the correct way to do this in PHP, or is there a better and shorter way?
I created a pastebin as a response to the first answer: pastebin.com/Y5vNvKKL
This question is not anymore just about a less goofy way to write this: Now the question is:Why does sort() in array_work() not give the same result as sort() in foreach?
By the way: This is about finding the partitions of multisets.
I'd approach it like this:
array_walk($arr, 'sort');
$deduped = array();
foreach ($arr as $val) {
$deduped[serialize($val)] = $val;
}
$arr = array_values($deduped);
This question already has answers here:
PHP: How to sort the characters in a string?
(5 answers)
Closed 8 years ago.
For example we have the following words: hey, hello, wrong
$unsorted = array("eyh", "lhleo", "nrwgo");
I know that I could use asort to sort the array alphabetically, but I don't want that.
I wish to take the elements of the array and sort those, so that it would become something like this:
$sorted = array("ehy", "ehllo", "gnorw"); // each word in the array sorted
hey sorted = ehy
hello sorted = ehllo
wrong sorted = gnorw
As far as I know, the function sort will only work for arrays, so if you attempt to sort a word using sort, it will produce an error. If I had to assume, I will probably need to use a foreach along with strlen and a for statement or something similar, but I am not sure.
Thanks in advance!
function sort_each($arr) {
foreach ($arr as &$string) {
$stringParts = str_split($string);
sort($stringParts);
$string = implode('', $stringParts);
}
return $arr;
}
$unsorted = array("eyh", "lhleo", "nrwgo");
$sorted = sort_each($unsorted);
print_r($sorted); // returns Array ( [0] => ehy [1] => ehllo [2] => gnorw )
$myArray = array("eyh", "lhleo", "nrwgo");
array_walk(
$myArray,
function (&$value) {
$value = str_split($value);
sort($value);
$value = implode($value);
}
);
print_r($myArray);
Try this
$unsorted = array("eyh", "lhleo", "nrwgo");
$sorted = array();
foreach ($unsorted as $value) {
$stringParts = str_split($value);
sort($stringParts);
$sortedString = implode('', $stringParts);
array_push($sorted, $sortedString);
}
print_r($sorted);
See this:
$q = 'blah';
for($k = 0; $k < count($results_array); $k++){
$results_array_ . $k = explode(',', $results_array[$k]);
foreach($results_array_ . $k as $key => $value){
if (stripos($value, $q) === false) {
unset($results_array_ . $k[$key]);
break;
}
}
}
On line 3 I'm simply using "$results_array_ . $k" and it's working just fine, but on line 6 I'm getting PHP parse errors on "unset($results_array_ . $k[$key])", why is this happening?
I appreciate anykind of help
Why I'm doing it:
I have an array named results_array:
var_dump($results_array):
0 => php,mysql,jquery,ruby,html,css,lamp
1 => mouse,keyboard,laptop,pad
2 => table,sofa,caption
and I have a $q which stands for query, I want to search in the $results_array and remove the items which has nothing to do with the query, so if I set $q=a then results array should be this:
0 => lamp
1 => keyboard,laptop,pad
3 => table,sofa,caption
now, I want to put the above results in each index of the results_array, at the end results_array should be:
0 => lamp
1 => keyboard
2 => laptop
3 => pad
4 => table
5 => sofa
6 => caption
Answer to original question
unset expects its argument to be a direct reference to a value, e.g. $var or $array['key']. If you want to dynamically create the argument based on other values, you 'll have to use variable variable syntax:
unset(${$results_array_ . $k[$key]});
This will get rid of the warning, but it still won't make the code work because it's fundamentally flawed. Line 3 which you mention reads:
$results_array_ . $k = explode(',', $results_array[$k]);
What this does is explode an array into $k and then concatenate $results_array_ with $k and... throw away the result. You could just as easily have written
$k = explode(',', $results_array[$k]);
and it would work the same (except possibly not giving an E_NOTICE that $_results_array_ does not exist).
So, it seems that you have a misunderstanding of how some PHP fundamentals work. It would be best if you asked another question that explains what you are trying to do, in order to determine what would be a good way of doing it.
Answer to current question
Let's take the steps one at a time:
Take the array of strings and turn each string into an array with explode, making an array of arrays. You can do this with array_map or a simple foreach.
"Flatten" the array of arrays into one big array. You can do this with array_merge or array_merge_recursive (the details will be a bit different, the idea is the same).
Search the flattened array and filter out uninteresting elements with array_filter.
If necessary, reindex the filtered array so that it has consecutive numeric keys with array_values.
Here's code that does this, albeit a little differently (I am doing steps 1 and 2 at the same time in the first line using array_reduce):
$array = (...);
$array = array_reduce($array, function(&$result, $item) {
return array_merge($result, explode(',', $item));
}, array());
$array = array_filter($array, function($item) use ($string) {
return strpos($item, $string) !== false;
});
$result = array_values($array);
A version that does the same without using fancy functions:
// Step 1
foreach($array as &$row) {
$row = explode(',', $row);
}
unset($row);
// Step 2
$array = call_user_func_array('array_merge_recursive', $array);
// Step 3
foreach ($array as $k => $v) {
if(strpos($v, 'a') === false) unset($array[$k]);
}
// Step 4
$array = array_values($array);
I know there is array_unique function, but I want to remove duplicates. Is there a built-in function or do I have to roll my own.
Example input:
banna, banna, mango, mango, apple
Expected output:
apple
You can use a combination of array_unique, array_diff_assoc and array_diff:
array_diff($arr, array_diff_assoc($arr, array_unique($arr)))
You can use
$singleOccurences = array_keys(
array_filter(
array_count_values(
array('banana', 'mango', 'banana', 'mango', 'apple' )
),
function($val) {
return $val === 1;
}
)
)
See
array_count_values — Counts all the values of an array
array_filter — Filters elements of an array using a callback function
array_keys — Return all the keys or a subset of the keys of an array
callbacks
Just write your own simple foreach loop:
$used = array();
$array = array("banna","banna","mango","mango","apple");
foreach($array as $arrayKey => $arrayValue){
if(isset($used[$arrayValue])){
unset($array[$used[$arrayValue]]);
unset($array[$arrayKey]);
}
$used[$arrayValue] = $arrayKey;
}
var_dump($array); // array(1) { [4]=> string(5) "apple" }
have fun :)
If you want to only leave values in the array that are already unique, rather than select one unique instance of each value, you will indeed have to roll your own. Built in functionality is just there to sanitise value sets, rather than filter.
You want to remove any entries that have duplicates, so that you're left with only the entries that were unique in the list?
Hmm it does sound like something you'll need to roll your own.
There is no existing function; You'll have to do this in two passes, one to count the unique values and one to extract the unique values:
$count = array();
foreach ($values as $value) {
if (array_key_exists($value, $count))
++$count[$value];
else
$count[$value] = 1;
}
$unique = array();
foreach ($count as $value => $count) {
if ($count == 1)
$unique[] = $value;
}
The answer on top looks great, but on a side note: if you ever want to eliminate duplicates but leave the first one, using array_flip twice would be a pretty simple way to do so. array_flip(array_flip(x))
Only partially relevant to this specific question - but I created this function from Gumbo's answer for multi dimensional arrays:
function get_default($array)
{
$default = array_column($array, 'default', 'id');
$array = array_diff($default, array_diff_assoc($default, array_unique($default)));
return key($array);
}
In this example, I had cached statuses and each one other than the default was 0 (the default was 1). I index the default array from the IDs, and then turn it into a string. So to be clear - the returned result of this is the ID of the default status providing it's in the same part of the multi dimensional array and not the key of it
PHP.net http://php.net/manual/en/function.array-unique.php
array array_unique ( array $array [, int $sort_flags = SORT_STRING ] )
Takes an input array and returns a new array without duplicate values.
New solution:
function remove_dupes(array $array){
$ret_array = array();
foreach($array as $key => $val){
if(count(array_keys($val) > 1){
continue;
} else {
$ret_array[$key] = $val;
}
}