Push only unique values into an array while looping
Asked Answered
G

10

61

I am using the following loop to add items to an an array. I would like to know if it is somehow possible to not add $value to the $liste array if the value is already in the array?

$liste = array();
foreach($something as $value){
     array_push($liste, $value);
}
Gwendolyn answered 10/4, 2012 at 20:31 Comment(1)
This is a bit vague on details. It kind of depends on what $value is. Is it a scalar value? Is it consistently an integer? a string? Depending on this vital detail, there may be more efficient ways than to make iterated calls of in_array().Eustashe
M
122

You check if it's there, using in_array, before pushing.

foreach($something as $value){
    if(!in_array($value, $liste, true)){
        array_push($liste, $value);
    }
}

The ,true enables "strict checking". This compares elements using === instead of ==.

Meyerbeer answered 10/4, 2012 at 20:32 Comment(8)
Be aware that, if $value is numeric and happens to be the same as one of the (numeric) keys in $liste, in_array() can return true even if no such value is in the array. I suggest using array_search() instead and strong-comparing the result against false.Porch
@Jazz: What are you talking about? in_array only searches array values, not keys. ideone.com/JjkuPMeyerbeer
@Rocket, I see your results, but in the past I have received different results. It may be that the issue was fixed before 5.2.11.Porch
@Jazz: That was never an issue, not even in PHP 4. The issue was probably in your code.Meyerbeer
@Rocket, See this link or this link for people who have experienced issues with in_array().Porch
@Jazz: Heh, interesting. Those issues can be fixed by adding ,true to in_array to enable "strict checking". Also, those issues have nothing to do with the keys in the array, they have to do with PHP's weird "type juggling". P.S. array_search will have the same issue(s).Meyerbeer
@Rocket, I went back and looked. You are correct that I am mischaracterizing the issue with in_array() -- it does not have issues with numeric keys, but with loose type conversion. My mistake! In the code where I used it before, using strict mode was not an option (I needed '2' to compare the same as 2 but not the same as '2thing'). I still recommend that new PHP developers use array_search() if only because it has fewer "gotcha's" than in_array(). The moral is -- whatever you use, make sure you know when it won't work.Porch
@Jazz: array_search has the same "gotcha's" as in_array, though.Meyerbeer
B
32

Two options really.

Option 1: Check for each item and don't push if the item is there. Basically what you're asking for:

foreach($something as $value) {
    if( !in_array($value,$liste)) array_push($liste,$value);
}

Option 2: Add them anyway and strip duplicates after:

foreach($something as $value) {
    array_push($liste,$value);
}
$liste = array_unique($liste);

By the look of it though, you may just be looking for $liste = array_unique($something);.

Birthstone answered 10/4, 2012 at 20:33 Comment(2)
Which of these two options would be more efficient?Superclass
@Superclass It seems that it depends on the probability of having duplicates. If the probability of an element being duplicated is higher than that of it being not duplicated, then the first option is certainly more efficient IMHO. However, if it is not the case, then the second one looks lighter.Absence
M
11

As this question is using not the best practice code to begin with - I find all the answers here to be over-complicated.

Solving code in question:

Basically what is tried to do in question itself is filtering out repetitions. Better approach:

$liste = array_unique($something);

If adding elements to an array that is not empty:

$liste = array_unique(array_merge($liste, $something));

If you are using array_push():

Unless you are actually using return value of array push you should really use:

$liste[] = $value;

for shorter syntax and minor performance increase

Mitre answered 13/7, 2018 at 7:58 Comment(1)
Liking the brevity/elegance of this. Another one-liner could be: array_push($liste,...array_diff($something,$liste)); (No idea how this would compare on performance)Bimestrial
S
5

maybe you want to use it as an associative array instead. it's implemented as (something like) a hash table, so you get constant insert time instead of linear.

function find_uniq( $something ) {
    foreach($something as $value){
         $liste[$value]++;
    }
    return array_keys( $liste );
}

If you want to suppress the warning, add the @ sign in line three.

If you want to avoid the warning, you need to check for existence first:

function find_uniq( $something ) {
    foreach($something as $value){
      if (isset($liste[$value]))
        $liste[$value]++;
      else
        $liste[$value] = 1;
    }
    return array_keys( $liste );
}
Selfservice answered 10/4, 2012 at 20:33 Comment(0)
P
5

The right answer is much simpler. Push everything, but then use array_unique() function:

array_push($array, $new_member);
$array = array_unique($array);
Peristalsis answered 9/8, 2017 at 0:33 Comment(0)
P
3

You can simply check this condition before calling array_push(). Use array_search() and use a strong comparison to false to see if the value is present:

foreach( $something as $value ){
    if( array_search( $value, $liste, true ) === false ){
        array_push( $liste, $value );
    }
}

(By the way: Add ,true to array_search to use "strict checking". This will use === for comparisons instead of ==)

Porch answered 10/4, 2012 at 20:35 Comment(6)
I don't know where you heard that info about in_array, but it's completely wrong. in_array only searches values, not keys. ideone.com/JjkuPMeyerbeer
@Rocket, I see your results, but in the past I have received different results. It may be that the issue was fixed before 5.2.11.Porch
@Jazz: You must have done something wrong in your code, that was never an issue, not even in PHP 4.Meyerbeer
@Rocket, See this link or this link for people who have experienced issues with in_array(). I can assure you that when I encountered this issue about three years ago, I verified quite thoroughly that the issue was not in my code.Porch
@Jazz: Those issues have nothing to do with the keys in the array, they have to do with PHP's weird "type juggling". array_search will have the same issue(s). You need to add ,true to enable "strict checking" to fix this. Otherwise it uses == to compare (and '2dudes' == 2).Meyerbeer
@Jazz: I edited your answer with the results of our discussion :-)Meyerbeer
J
2

I have another solution for you! You can use keys as values And keys will never be duplicated.

$arr = ["A" => true, "B" => true, "C" => true];

$item = "A";
$arr[$item] = true;

Usage:

foreach($arr as $value => $helper){
    echo $value;
}

Set class

OK, Let me write a class for you! The arrays do not allow duplicated items are called sets.

class Set{
    private $countainer;

    public function get(){
        return $this->container;
    }
    public function push($item){
        $this->container[$item] = true;
    }
    public function delete($item){
        unset($this->container[$item]);
    }
}

Note: This will not work for associative arrays and values.

Jackass answered 1/8, 2019 at 8:34 Comment(0)
D
1

Great answers are already present above, but if you have multiple array_push() all over your code, it would be a pain to write if(in_array()) statements every time.

Here's a solution that will shorten your code for that case: Use a separate function.

function arr_inserter($arr,$add){ //to prevent duplicate when inserting
    if(!in_array($add,$arr))
        array_push($arr,$add);
    return $arr;
}

Then in all your array_push() needs, you can call that function above, like this:

$liste = array();
foreach($something as $value){
    $liste = arr_inserter($liste, $value);
}

If $value is already present, $liste remains untouched.

If $value is not yet present, it is added to $liste.

Hope that helps.

Dibucaine answered 10/4, 2012 at 20:31 Comment(0)
D
1

Save logic and improve speed by keeping it logic-less. Just keep overwriting.

$list = array();
foreach ($something as $value) {
  if (!is_object($value) && !is_array($value)) {
    $list[$value] = $value
  }
}
$list = array_values($list);
Dowson answered 6/2, 2015 at 4:37 Comment(4)
This works fine, as long as $value (as key) is not an object or arrayPeriostitis
This is a pretty decent solution, but you can see that you no longer have a logic-less solution, right? After the latest edit, this does not seem to be the most elegant solution anymore.Stringendo
That's true it does include some logic in each loop now :( I'd need to see some perf testing to know if this is the right approach.Dowson
While this can be efficient, there are some fringe cases whereby key collisions will damage the data. For one instance, floats will be truncated to integers -- so data loss is possible. is_scalar() will improve the "elegance".Eustashe
E
0

You can use values as temporary keys, so long as the $something array does not contain:

  1. non-scalar values (objects/arrays/etc. cannot be used as keys) or
  2. values that will be mutated when used as an array keys (floats get truncated, nulls become empty strings, and booleans become ints)
  3. a mix of numeric strings and integers that will be loosely evaluated as equal (2 vs "2")

(Bad Demo)


Code: (Good Demo)

$something = [3, 2, 1, 3, 6, 5, 1, 1];
$liste = [];
foreach ($something as $value) {
     $liste[$value] = $value;
}

Output:

array (
  3 => 3,
  2 => 2,
  1 => 1,
  6 => 6,
  5 => 5,
)

The above will absolutely perform better than any other approach on this page that is using a duplicate-checking technique. PHP will not allow duplicated keys on any single level of an array, so it will merely overwrite a re-encountered value.

If the new keys do not impact future processing, leave them as they are, otherwise call array_values() to re-index the array.

Eustashe answered 29/8, 2022 at 21:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.