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);
}
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
Marc
  • 9,217
  • 21
  • 67
  • 90
  • 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()`. – mickmackusa Nov 29 '21 at 00:57

10 Answers10

120

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 ==.

gen_Eric
  • 223,194
  • 41
  • 299
  • 337
  • 3
    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`. – Jazz Apr 10 '12 at 20:37
  • 4
    @Jazz: What are you talking about? `in_array` only searches array values, not keys. http://ideone.com/JjkuP – gen_Eric Apr 10 '12 at 20:51
  • @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. – Jazz Apr 10 '12 at 22:32
  • 1
    @Jazz: That was never an issue, not even in PHP 4. The issue was probably in your code. – gen_Eric Apr 10 '12 at 22:39
  • @Rocket, See [this link](http://us2.php.net/manual/en/function.in-array.php#106319) or [this link](http://us2.php.net/manual/en/function.in-array.php#101976) for people who have experienced issues with `in_array()`. – Jazz Apr 10 '12 at 22:40
  • @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). – gen_Eric Apr 10 '12 at 22:42
  • 3
    @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. – Jazz Apr 10 '12 at 22:46
  • @Jazz: `array_search` has the same "gotcha's" as `in_array`, though. – gen_Eric Apr 10 '12 at 22:49
31

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);.

Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
  • 3
    Which of these two options would be more efficient? – kojow7 Oct 30 '17 at 04:28
  • @kojow7 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. – Omar Trkzi Jun 20 '22 at 11:19
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

NoOorZ24
  • 2,914
  • 1
  • 14
  • 33
  • 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) – Headbank Jul 23 '22 at 15:47
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 );
}
bjelli
  • 9,752
  • 4
  • 35
  • 50
5

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

array_push($array, $new_member);
$array = array_unique($array);
Nick
  • 207
  • 3
  • 11
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 ==)

gen_Eric
  • 223,194
  • 41
  • 299
  • 337
Jazz
  • 1,435
  • 1
  • 15
  • 23
  • I don't know where you heard that info about `in_array`, but it's completely wrong. `in_array` *only* searches **values**, not **keys**. http://ideone.com/JjkuP – gen_Eric Apr 10 '12 at 20:58
  • 1
    @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. – Jazz Apr 10 '12 at 22:30
  • @Jazz: You must have done something wrong in your code, that was never an issue, not even in PHP 4. – gen_Eric Apr 10 '12 at 22:37
  • @Rocket, See [this link](http://us2.php.net/manual/en/function.in-array.php#106319) or [this link](http://us2.php.net/manual/en/function.in-array.php#101976) 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. – Jazz Apr 10 '12 at 22:41
  • @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`). – gen_Eric Apr 10 '12 at 22:46
  • @Jazz: I edited your answer with the results of our discussion :-) – gen_Eric Apr 10 '12 at 22:52
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.

Amir Fo
  • 5,163
  • 1
  • 43
  • 51
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.

ITWitch
  • 1,729
  • 5
  • 20
  • 38
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);
doublejosh
  • 5,548
  • 4
  • 39
  • 45
  • This works fine, as long as $value (as key) is not an object or array – gradosevic Oct 20 '16 at 17:35
  • 1
    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. – David Nov 22 '17 at 15:43
  • 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. – doublejosh Nov 30 '17 at 01:30
  • 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". – mickmackusa Jul 17 '21 at 10:53
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.

mickmackusa
  • 43,625
  • 12
  • 83
  • 136