I'm kind of stuck here on what I think must have quite a simple solution.
Say I have an array:
$A = array(1, 1, 2, 4, 6, 7, 7, 7, 13);
How could I possibly remove all of the values that occur more than once?
So I'm left with an array that looks like this
$A = array(2, 4, 6, 13);
I've tried using array unique, but that just removes duplicates leaving you with a single value. I need to use the following logic: if there are any values that match - then remove all of the values that match.
You could always try something like this.
$A = array(1, 1, 2, 4, 6, 7, 7, 7, 13);
$A = array_count_values($A);
foreach($A as $key => $value) {
if($value > 1)
unset($A[$key]);
}
$A = array_keys($A);
print_r($A);
edit: fixed error
Array
(
[0] => 2
[1] => 4
[2] => 6
[3] => 13
)
You can use array_filter() with a custom callback to filter out the array values which repeat more than once:
function removeDuplicates($array) {
$values = array_count_values($array);
return array_filter($array, function($item) use ($values) {
return $values[$item] === 1;
});
}
Usage:
$A = array(1, 1, 2, 4, 6, 7, 7, 7, 13);
print_r( removeDuplicates($A) );
Output:
Array
(
[2] => 2
[3] => 4
[4] => 6
[8] => 13
)
Demo.
You can do this with abit of coding.
First see this SO post to get a list of all the duplicates using array_unique:
php return only duplicated entries from an array
Then you'll have to loop through the duplicates returned from the link above and do an array_search to return the index of the values and then array_splice to actually remove it.
I don't know of any code that will do this in one step for you.
Try this (with PHP >= 5.3):
$A = array_keys(array_filter(
array_count_values($A),
function ($count)
{
return $count == 1;
}
));
Explanation:
array_count_values returns an array using the values of array as keys and their frequency in array as values.
array_filter Iterates over each value in the array passing them to the callback function (in this case anonymous function) . If the frequency is 1, the current value from array is returned into the result array.
array_keys returns the keys from the array, in this case the values with frequency equal to 1.
So, the compressed "one-line" form is:
$A=array_keys(array_filter(array_count_values($A),function($c){return $c==1;}));
Related
How can I calculate the sum of all elements in an array, then append that sum as a new element to the original array?
For example, the sum of [6,7,8] is 21 so the array should become [6,7,8,21].
Just push the returned value from array_sum() onto the end of the array.
Code: (Demo)
$array = [6,7,8];
$array[] = array_sum($array);
var_export($array);
Output:
array (
0 => 6,
1 => 7,
2 => 8,
3 => 21,
)
If you are expecting 15 by adding the final two elements, then use this:
$array = [6,7,8];
$array[] = array_sum(array_slice($array, -2));
var_export($array);
// [6, 7, 8, 15]
You could create a function to do this, like:
<?php
function sumAppend ( &$array)
{
$result = array_sum ( $array);
$array[] = $result;
return $result;
}
?>
I have an array like so:
[5, 2, 9]
However, I need this array:
[0 => 5, 1 => 2, 2 => 9]
So I need the index as key. Is there a function to achieve this? Now I create an empty array manually and I use array_push through a foreach loop. It works, however this doesn't seem elegant.
Is there a better solution?
$array = [5, 2, 9];
print_r($array);
outputs:
Array
(
[0] => 5
[1] => 2
[2] => 9
)
if you print array in loop you can see default key
$arr=[5, 2, 9];
foreach($arr as $key=>$val){
echo 'Key='.$key.','.'val='.$val.'<br/>';
}
OUTPUT
Key=0,val=5
Key=1,val=2
Key=2,val=9
Also if you echo using key like
$arr=[5, 2, 9];
echo $arr[1];
output
2
Use array_combine,
At first, create an array of values,
$values = array(5, 2, 9);
Now, create an array of keys,
$keys = array(0, 1, 2);
After that, Combine two array to get result,
$result = array_combine ( array $keys , array $values );
Your array already has the keys based off its position in the array
$test = [5, 2, 9];
print_r($test);
Array ( [0] => 5 [1] => 2 [3] => 9 )
echo $test[0]; = 5
echo $test[1]; = 2
echo $test[3]; = 9
I'm probably [super]overthinking this. I'm trying to analyze an array with values like [1,9], [4,6] [5,5], [6,4], [9,1] and duplicate digits (I'm having a super brain fart and can't even remember the term for numbers like this) remove (the last two) so that only [1,9], [4,6] [5,5] are printed.
I was thinking that turning this array into a string and using preg_match, but I'm pretty sure this wouldn't work even if I had the correct regex.
If you have an array of pairs like this:
$x = array(
array(1,9),
array(4,6),
array(5,5),
array(6,4),
array(9,1)
);
Here is one way to get the unique pairs:
foreach ($x as $pair) {
sort($pair);
$unique_pairs[implode(',', $pair)] = $pair;
}
This uses string representations of each sorted pair as keys in a new array, so the result will have distinct values by definition.
As far as the printing them out part of your question, once you have the unique values you can loop over them and print them out in whichever format you like, for example:
foreach ($unique_pairs as $pair) { vprintf("[%d,%d]<br>", $pair); }
It looks like elements are distributed symmetrically.
We can cut the array in two halves and get only the first half with array_slice():
$array = array(
array(1,9),
array(4,6),
array(5,5),
array(6,4),
array(9,1),
);
print_r(array_slice($array, 0, ceil(count($array) / 2)));
Result:
Array(
[0] => Array(
[0] => 1
[1] => 9
)
[1] => Array(
[0] => 4
[1] => 6
)
[2] => Array(
[0] => 5
[1] => 5
)
)
Demo at Codepad.
ceil() is used to round the number up to the next highest integer if there is an even number of items in the array. Example: if there is 3 items in the array, 5 / 2 will return 2.5, we want 3 items so we use ceil(2.5) which gives 3.
Example with 3 items:
$array = array(
array(1,9),
array(5,5),
array(9,1),
);
print_r(array_slice($array, 0, ceil(count($array) / 2)));
Result:
Array(
[0] => Array(
[0] => 1
[1] => 9
)
[1] => Array(
[0] => 5
[1] => 5
)
)
Example with 4 items:
$array = array(
array(1,9),
array(7,7),
array(7,7),
array(9,1),
);
print_r(array_slice($array, 0, ceil(count($array) / 2)));
Result:
Array(
[0] => Array(
[0] => 1
[1] => 9
)
[1] => Array(
[0] => 7
[1] => 7
)
)
If I'm correct in understanding what you are trying to do, you want to remove the final 2 elements from the array?
There is a function in PHP called array_pop that removes the final element from the array.
$array = array_pop($array);
So if you run this twice, you will remove the final 2 elements from the array.
This is how I'd do it (and I hope I am not overthinking this :))
$stringArray = array();
$stringArray[] = '1,9';
$stringArray[] = '4,6';
$stringArray[] = '5,5';
$stringArray[] = '6,4';
$stringArray[] = '9,1';
foreach($stringArray as &$numString) {
$numString = explode(',', $numString);
usort($numString, function($a, $b) {return $a - $b;});
$numString = implode(',', $numString);
}
$a = array_unique($a);
print_r($a);
You basically explode every element into a subarray, sort it and then implode it back. After calling the array_unique, you're left with unique values in the array.
The output would be
Array
(
[0] => 1,9
[1] => 4,6
[2] => 5,5
)
The result you suggest treats [a,b] as equivalent to [b,a] which makes the problem a lot more complex. The code below gives the result you asked for, but without really understanding what the problem is that you are trying to fix and whether [1,9] is equivalent to [9,1] in the solution:
$a=array(array(1,9),array(4,6),...
$dup=array();
for ($i=0; $i<count($a) -1; $i++) {
for ($j=$i+1; $j<count($a); $j++) {
if (($a[$i][0]==$a[$j[0] && $a[$i][1]==$a[$j[1])
|| ($a[$i][0]==$a[$j[1] && $a[$i][1]==$a[$j[0])) {
$dup[]=$j;
}
}
}
foreach ($dup as $i) {
unset($a[$i]);
}
So I'm actually going to assume your question to have a different meaning than everyone else did. I believe what you're asking is:
How do you filter out array items where a reverse of the item has already been used?
<?php
// The example set you gave
$numberSets = [[1, 9], [4, 6], [5, 5], [6, 4], [9, 1]];
// Initialize an empty array to keep track of what we've seen
$keys = [];
// We use array filter to get rid of items we don't want
// (Notice that we use & on $keys, so that we can update the variable in the global scope)
$numberSets = array_filter($numberSets, function($set) use(&$keys) {
// Reverse the array
$set = array_reverse($set);
// Create a string of the items
$key = implode('', $set);
// Get the reverse of the numbers
$reversedKey = strrev($key);
// If the palindrome of our string was used, return false to filter
if (isset($keys[$reversedKey])) {
return false;
}
// Set the key so it's not used again
// Since $keys is being passed by reference it is updated in global scope
$keys[$key] = true;
// Return true to NOT filter this item, since it or it's reverse were not matched
return true;
});
var_dump($numberSets);
I want to unset every second item from an array. I don't care about if the keys are reordered or not.
Of course I want it fast and elegant. Is it maybe possible without a loop and temporary variables?
My own solution so far:
for ( $i = 1; isset($arr[$i]); $i += 2) {
unset($arr[$i]);
}
The pro is, that it needs no if-statement, the con that a variable ($i) is still needed and it works only if the keys are numeric and without gaps.
function arr_unset_sec(&$arr, $key)
{
if($key%2 == 0)
{
unset($arr[$key]);
}
}
array_walk($arr, 'arr_unset_sec');
Assuming $arr may be some array. Check this piece of code.
If you have an array like
Array
(
[0] => test1
[1] => test2
[2] => test3
[3] => test4
[4] => test5
)
Then you can go with below code. It will remove every second item of array.
$i = 1;
foreach ($demo_array as $key => $row) {
if($i%2 == '0')
{
unset($demo_array[$key]);
}
$i++;
}
Hope this will helps you. Let mee know if you need any further help on it.
Another solution without a loop:
$arr = array('a', 'b', 'c', 'd', 'e');
$arr = array_filter( $arr, function($k) { return $k % 3 === 0; }, ARRAY_FILTER_USE_KEY);
Pro, it needs no loop. Cons, it is a lot slower than my other version (with a for loop), looks a bit scary and depends again on the keys.
I'll provide two methods (array_filter() and a foreach() loop) which will leverage the condition $i++%$n to target the elements to be removed.
Both methods will work on indexed and associative arrays.
$i++ This is post-incrementation. Effectively, the value will be evaluated first, then incremented second.
% This is the modulo operator - it returns the "remainder" from the division of the leftside value from the rightside value.
The return value from the condition will either be 0 or a positive integer. For this reason, php's inherent "type juggling" feature can be used to convert 0 to false and positive integers as true.
In the array_filter() method, the use() syntax must use &$i so that the variable is "modifiable". Without the &, $i will remain static (unaffected by post-incrementation).
In the foreach() method, The condition is inverted !() in comparison to the array_filter() method. array_filter() wants to know what to "keep"; foreach() wants to know what to unset().
Code: (Demo)
// if:$n=2 $n=3 $n=4 $n=5
$array=['first'=>1,
2, // remove
'third'=>3, // remove
'fourth'=>4, // remove remove
5, // remove
6, // remove remove
'seventh'=>7,
'eighth'=>8, // remove remove
'ninth'=>9]; // remove
// if $n is 0 then don't call anything, because you aren't attempting to remove anything
// if $n is 1 then you are attempting to remove every element, just re-declare as $array=[]
for($n=2; $n<5; ++$n){
$i=1; // set counter
echo "Results when filtering every $n elements: ";
var_export(array_filter($array,function()use($n,&$i){return $i++%$n;}));
echo "\n---\n";
}
echo "\n\n";
// Using a foreach loop will be technically faster (only by a small margin) but less intuitive compared to
// the literal/immediate interpretation of "array_filter".
for($n=2; $n<5; ++$n){
$i=1;
$copy=$array;
foreach($copy as $k=>$v){
if(!($i++%$n)) unset($copy[$k]); // or $i++%$n==0 or $i++%$n<1
}
echo "Results when unsetting every $n elements: ";
var_export($copy);
echo "\n---\n";
}
Output:
Results when filtering every 2 elements: array (
'first' => 1,
'third' => 3,
1 => 5,
'seventh' => 7,
'ninth' => 9,
)
---
Results when filtering every 3 elements: array (
'first' => 1,
0 => 2,
'fourth' => 4,
1 => 5,
'seventh' => 7,
'eighth' => 8,
)
---
Results when filtering every 4 elements: array (
'first' => 1,
0 => 2,
'third' => 3,
1 => 5,
2 => 6,
'seventh' => 7,
'ninth' => 9,
)
---
Results when unsetting every 2 elements: array (
'first' => 1,
'third' => 3,
1 => 5,
'seventh' => 7,
'ninth' => 9,
)
---
Results when unsetting every 3 elements: array (
'first' => 1,
0 => 2,
'fourth' => 4,
1 => 5,
'seventh' => 7,
'eighth' => 8,
)
---
Results when unsetting every 4 elements: array (
'first' => 1,
0 => 2,
'third' => 3,
1 => 5,
2 => 6,
'seventh' => 7,
'ninth' => 9,
)
---
$n = 1
for( $i=$n;$i=$n;)
{
unset($arOne[$i]);
unset($arSnd[$i]);
unset($arThd[$i]);
break;
}
I think this will also perfectly.
Does anyone know how to sort an array into alternating smallest largest values?
I.E.
Array (10, 2, 5, 1, 30, 1, 7)
Should be :
(30, 1, 10, 1, 7, 2, 5)
EDIT:
Forgot to mention the arrays are associative, so:
Array("A"=>10, "B"=>2, "C"=>5, "D"=>1, "E"=>30, "F"=>1, "G"=>7)
Should become:
("E"=>30, "D"=>1, "A"=>10, "F"=>1, "G"=>7, "B"=>2, "C"=>5)
Sort your array then push elements from beginning and end of the array alternatively:
<?php
$myArray = array(10, 2, 5, 1, 30, 1, 7);
sort($myArray );
$count=sizeof($myArray );
$result= array();
for($counter=0; $counter * 2 < $count; $counter++){
array_push($result, $myArray[$count - $counter - 1]);
//check if same elements (when the count is odd)
if ($counter != $count - $counter - 1) {
array_push($result, $myArray[$counter]);
}
}
print_r ($result);
?>
returns:
Array ( [0] => 30 [1] => 1 [2] => 10 [3] => 1 [4] => 7 [5] => 2 [6] => 5 )
<?php
$x = array(10, 2, 5, 1, 30, 1, 7);
// First sort
sort($x);
// Then pick highest and lowest from the back and front of the array
// until it is empty.
$z = array();
while (count($x) > 0){
$z[] = array_pop($x);
if (count($x) > 0) // <- For arrays with an odd number of elements.
$z[] = array_shift($x);
}
var_dump($z);
I can't tell you the exact syntax, my php is very rusty, but what you can do:
Sort your array in descending order
Split in in half, let say array A and B;
Create a new array and add each element from A and B in order $A[i], $B[count($B)-1-i]
This should give you what you need
There is no predefined way to do this. However, php allows for a user sort function usort which you can customise to sort the array in the way you require.