I have an array with possible duplicate values, and I want not only to remove them (i use array_unique for that), but extract them in anothr array.
i.e.
$a = array(1,2,2,3,4,4,5,6,6,6);
$b = array_unique($a); // has 1,2,3,4,5,6
I want a third array ($c) with the duplicates only
that is, with [2,4,6] or [2,4,6,6] (either would do)
whats the easiest way of doing it?
I tried $c = array_diff($a,$b), but gives an empty array, since it is removing all of the occurrences of $b from $a (because, of course, they occur at least once in $b)
I also thought of array_intersect, but it result in an array exactly like $a
Is there a direct function in php to achieve this? How to do it?
I also found such solution on Internet:
$c = array_unique( array_diff_assoc( $a, array_unique( $a ) ) );
But it doesn't seem easy to understand
You can use array_count_values to count the # of occurrences of each element and use array_filter to only keep those that occur more than once.
$a = array(1,2,2,3,4,4,5,6,6,6);
$b = array_count_values($a);
$c = array_filter($b,function($val){ return $val > 1; });
$c = array_keys($c);
print_r($c);
If your input array is sorted you can find dupes by looping through the array and checking if the previous element is equal to the current one
$a = array(1,2,2,3,4,4,5,6,6,6);
$dupes = array();
foreach($a as $i => $v) {
if($i > 0 && $a[--$i] === $v)
$dupes[] = $v;
}
print_r($dupes);
Related
I am using array_diff() to take values out of array1 which are found in array2. The issue is it removes all occurrences from array1, as the PHP documentations makes note of. I want it to only take out one at a time.
$array1 = array();
$array1[] = 'a';
$array1[] = 'b';
$array1[] = 'a';
$array2 = array();
$array2[] = 'a';
It should return an array with one 'a' and one 'b', instead of an array with just 'b';
Just for the fun of it, something that just came to mind. Will work as long as your arrays contain strings:
$a = array('a','b','a','c');
$b = array('a');
$counts = array_count_values($b);
$a = array_filter($a, function($o) use (&$counts) {
return empty($counts[$o]) || !$counts[$o]--;
});
It has the advantage that it only walks over each of your arrays just once.
See it in action.
How it works:
First the frequencies of each element in the second array are counted. This gives us an arrays where keys are the elements that should be removed from $a and values are the number of times that each element should be removed.
Then array_filter is used to examine the elements of $a one by one and remove those that should be removed. The filter function uses empty to return true if there is no key equal to the item being examined or if the remaining removal count for that item has reached zero; empty's behavior fits the bill perfectly.
If neither of the above holds then we want to return false and decrement the removal count by one. Using false || !$counts[$o]-- is a trick in order to be terse: it decrements the count and always evaluates to false because we know that the count was greater than zero to begin with (if it were not, || would short-circuit after evaluating empty).
Write some function that removes elements from first array one by one, something like:
function array_diff_once($array1, $array2) {
foreach($array2 as $a) {
$pos = array_search($a, $array1);
if($pos !== false) {
unset($array1[$pos]);
}
}
return $array1;
}
$a = array('a', 'b', 'a', 'c', 'a', 'b');
$b = array('a', 'b', 'c');
print_r( array_diff_once($a, $b) );
probably an already discussed topic, but in Php I did not found an answer
Is there a simpler way to realize in what follows:
$a = array("hello","hello","Hello","world","worlD");
$p=array();
foreach( $a as $v ){
$p[strtolower($v)] = "";
}
print_r($p);
keep one single element, in small-case, for the array
something like:
$p = array_unique(array_map('strtolower', $a));
You can use array_flip to swap keys and values:
$a = array_flip(array_map('strtolower', $a));
I have two large arrays:
$a = array('a1','a2','a3','a4'); // and so on
$b = array('b1'=>'a1', 'b2'=>'a3', 'b3'=>'a1'); //
I would like to get the following result:
$a = array('a1'=>array('b1', 'b3'), 'a2'=>array(), 'a3'=>array('b2') );
I could just do:
foreach($a as $aa){
foreach($b as $bb){
// check with if then add to a
}
}
but it would get tremendously large with bigger numbers.
So it occurred to me that if i remove each 'b' element after being added to $a the next loops will be smaller, and i would cut on resources.
However when splicing the looped array, the index does not seem to get updated, and the next loop does not take into consideration that fact that it was cut down by 1.
How can I make this work, and also, is there a better way of fitting items of an array into the appropriate indexes of another array?
EDIT:
how would this be done if the structure of both $a and $b were:
$a[0]['Word']['id']=1;
$a[0]['Word']['sentence_id']=2;
$a[0]['Word']['word_string']='someWord';
$b[0]['Word']['id']=3;
$b[0]['Word']['sentence_id']=4;
$b[0]['Word']['word_string']='someWord';
// And i would like to list `b` like so:
$a[0]['list_of_bs']=array(b[0], b[1]);
//So that i can get:
echo $a[0]['list_of_bs']['Word']['id'];
// and to get result 3
and i would like it to be $a[0][Word][list_of_b]=array(b1,b2,b3) and each of the b's has it's own data in associative array.
Try this,
$a = array('a1','a2','a3','a4');
$b = array('b1'=>'a1', 'b2'=>'a3', 'b3'=>'a1');
foreach($a as $values)
{
$key = array_keys($b, $values);
$new_array[$values] = $key;
}
$new_array -> will be the result that you need.
No there is no other way which removes load from the server.
You need to do this in this way only.
Even array_walk also need to perform it like in the loopy way.
The way you put together the two loops is not well thought. Don't put them together but after each other:
foreach ($a as $aa) {
// transform a
}
foreach ($b as $bb){
// check with if then add to a
}
This will make count(a) + count(b) iterations instead of count(a) * count(b) iterations - which is less unless a and b have only one element.
Taking idea from #hakre ..
Why not loop through $b
new_arr = new array
foreach $b as $bb
new_arry($bb->val).push($bb->key)
foreach $new_arry as $nn
if $nn doesn't exist in $a then remove
I need to merge several arrays into a single array. The best way to describe what I'm looking for is "interleaving" the arrays into a single array.
For example take item one from array #1 and append to the final array. Get item one from array #2 and append to the final array. Get item two from array #1 and append...etc.
The final array would look something like this:
array#1.element#1
array#2.element#1
.
.
.
The "kicker" is that the individual arrays can be of various lengths.
Is there a better data structure to use?
for example,
function array_zip_merge() {
$output = array();
// The loop incrementer takes each array out of the loop as it gets emptied by array_shift().
for ($args = func_get_args(); count($args); $args = array_filter($args)) {
// &$arg allows array_shift() to change the original.
foreach ($args as &$arg) {
$output[] = array_shift($arg);
}
}
return $output;
}
// test
$a = range(1, 10);
$b = range('a', 'f');
$c = range('A', 'B');
echo implode('', array_zip_merge($a, $b, $c)); // prints 1aA2bB3c4d5e6f78910
If the arrays only have numeric keys, here's a simple solution:
$longest = max( count($arr1), count($arr2) );
$final = array();
for ( $i = 0; $i < $longest; $i++ )
{
if ( isset( $arr1[$i] ) )
$final[] = $arr1[$i];
if ( isset( $arr2[$i] ) )
$final[] = $arr2[$i];
}
If you have named keys you can use the array_keys function for each array and loop over the array of keys instead.
If you want more than two arrays (or variable number of arrays) then you might be able to use a nested loop (though I think you'd need to have $arr[0] and $arr[1] as the individual arrays).
I would just use array_merge(), but that obviously depends on what exactly you do.
This would append those arrays to each other, while elements would only be replaced when they have the same non-numerical key. And that might not be a problem for you, or it might be possible to be solved because of attribute order, since the contents of the first arrays' elements will be overwritten by the later ones.
If you have n arrays, you could use a SortedList, and use arrayIndex * n + arrayNumber as a sort index.
How else might you compare two arrays ($A and $B )and reduce matching elements out of the first to prep for the next loop over the array $A?
$A = array(1,2,3,4,5,6,7,8);
$B = array(1,2,3,4);
$C = array_intersect($A,$B); //equals (1,2,3,4)
$A = array_diff($A,$B); //equals (5,6,7,8)
Is this the simplest way or is there a way to use another function that I haven't thought of? My goal is to have an array that I can loop over, pulling out groups of related content (I have defined those relationships elsewhere) until the array returns false.
You've got it. Just use array_diff or array_intersect. Doesn't get much easier than that.
Edit:
For example:
$arr_1 = array_diff($arr_1, $arr_2);
$arr_2 = array_diff($arr_2, $arr_1);
Source
Dear easy and clean way
$clean1 = array_diff($array1, $array2);
$clean2 = array_diff($array2, $array1);
$final_output = array_merge($clean1, $clean2);
See also array_unique. If you concatenate the two arrays, it will then yank all duplicates.
Hey, even better solution: array _ uintersect.
This let's you compare the arrays as per array_intersect but then it lets you compare the data with a callback function.
Try to this
$a = array(0=>'a',1=>'x',2=>'c',3=>'y',4=>'w');
$b = array(1=>'a',6=>'b',2=>'y',3=>'z');
$c = array_intersect($a, $b);
$result = array_diff($a, $c);
print_r($result);