70

I'm looking for a simple way to create an array in php that will not allow duplicate entries, but allows for easy combining of other sets or arrays.

I'm mostly interested in whether such a feature exists in the language because writing my own wouldn't be difficult. I just don't want to if I don't need to.

devios1
  • 36,899
  • 45
  • 162
  • 260
  • 1
    Have a look at [Set](https://github.com/ihor/Nspl#set) from [Nspl](https://github.com/ihor/Nspl). – Ihor Burlachenko Feb 18 '16 at 21:10
  • 2
    Looks like it's built into PHP now? https://www.php.net/manual/en/class.ds-set.php – Connor Leech May 07 '19 at 18:22
  • 2
    @ConnorLeech And it looks like it does exactly what zrvan suggested. Interesting that it preserves insertion order though. You don’t usually see that on a `Set` class. – devios1 May 07 '19 at 18:33

6 Answers6

85

Just an idea, if you use the array keys instead of values, you'll be sure there are no duplicates, also this allows for easy merging of two "sets".

$set1 = array ('a' => 1, 'b' => 1, );
$set2 = array ('b' => 1, 'c' => 1, );
$union = $set1 + $set2;
zrvan
  • 7,533
  • 1
  • 22
  • 23
  • 1
    Interesting idea. Wonder if there are any downsides. – devios1 Nov 14 '11 at 21:44
  • For this particular usage, I don't think so, if anyone knows better, please tell. – zrvan Nov 14 '11 at 21:59
  • 2
    As this idea continuation: `function sum_sets($a, $b){return array_keys(array_flip($a)+array_flip($b));} print_r(sum_sets(array(1,2,3), array(3,4,5)));` – vp_arth Jul 28 '14 at 11:03
  • 3
    This would not work if you want to store `Objects` in the `Set`. `Associative arrays` do not allow having `Object` as keys. – kekko12 Apr 01 '18 at 14:18
  • 3
    I use `$my_set['a'] = 'a'` to insert values into a "set" instead of `$my_set['a'] = '1'`, so I don't care whether to ask for keys or values. – Thinkeye Apr 24 '18 at 16:06
  • This works well for integers and it's very quick compared to other options that require calling functions. I just ran it on a set 100k integers of which only 25k were unique and it finished in a very few seconds compared to 10s of seconds with calling in_array on each integer and an out of memory error using array_unique. – Night Owl Aug 08 '19 at 13:31
  • 3
    The downside is that you use additional memory to set the values, but you don't actually need the values. – nacholibre Dec 06 '19 at 09:15
  • The downside is that it only works for `string` and `int`, and not for `bool`, `null`, `resource`, objects, other arrays and anything else than `string|int` really. – Danon Apr 25 '22 at 12:45
16

The answer is no, there is not a native set solution inside PHP. There is a Set data structure, but that is not baseline PHP.

There is a convention for implementing sets using maps (i.e. associative arrays) in any language. And for PHP you should use true as the bottom value.

<?php

$left = [1=>true, 5=>true, 7=>true];
$right = [6=>true, 7=>true, 8=>true, 9=>true];

$union = $left + $right;
$intersection = array_intersect_assoc($left, $right);

var_dump($left, $right, $union, $intersection);
William Entriken
  • 37,208
  • 23
  • 149
  • 195
4

You can use array_combine for removing duplicates

$cars = array("Volvo", "BMW", "Toyota");
array_push($cars,"BMW");

$map = array_combine($cars, $cars);
Preetam Purbia
  • 5,736
  • 3
  • 24
  • 26
  • 3
    This is a really inefficient way of solving the problem. Moreover, you'll have to 'rememeber' to call `array_combine` everytime you need an array with unique values – kekko12 Apr 01 '18 at 14:20
2

I also had this problem and so have written a Class: https://github.com/jakewhiteley/php-set-object

As suggested, it does extend and ArrayObject and allow native-feeling insertion/iteration/removal of values, but without using array_unique() anywhere.

Implementation is based on the MDN JS Docs for Sets in EMCA 6 JavaScript.

Jake Whiteley
  • 495
  • 4
  • 10
2

The Set class.

https://www.php.net/manual/en/class.ds-set.php

Don't know when will it come out.

Charlie 木匠
  • 2,234
  • 19
  • 19
1

In Laravel there is a method unique in Collection class that may be helpful. From Laravel documentation:

$collection = collect([1, 1, 2, 2, 3, 4, 2]);
$unique = $collection->unique();
$unique->values()->all();
// [1, 2, 3, 4]
mp31415
  • 6,531
  • 1
  • 44
  • 34
  • 5
    But that is just a wrapper for array_unique really, see here https://github.com/laravel/framework/blob/5.3/src/Illuminate/Support/Collection.php#L1125 – mastazi Dec 07 '16 at 23:37
  • Laravel is not php, rather a php framework – gdm Jan 12 '22 at 17:33