9

I have an array with duplicate values in postgres. For example:

SELECT cardinality(string_to_array('1,2,3,4,4', ',')::int[]) as foo
=> "foo"=>"5"

I would like to get unique elements, for example:

SELECT cardinality(uniq(string_to_array('1,2,3,4,4', ',')::int[])) as foo
=> -- No function matches the given name and argument types. You might need to add explicit type casts.

Can I get unique elements of an array in postgres without using UNNEST ?

Benjamin Crouzier
  • 40,265
  • 44
  • 171
  • 236
  • whats wrong with UNNEST? using UNNEST you will be able to SELECT DISTINCT and be done with the job.. – Bartosz Bilicki Nov 16 '16 at 15:53
  • 1
    There is a specific `uniq(int[])` function in the [`intarray` module](https://www.postgresql.org/docs/current/static/intarray.html), but other than that, you have to use `unnest()`. – pozs Nov 16 '16 at 16:00

3 Answers3

14

I prefer this syntax (about 5% faster)

create or replace function public.array_unique(arr anyarray)
returns anyarray as $body$
    select array( select distinct unnest($1) )
$body$ language 'sql';

using:

select array_unique(ARRAY['1','2','3','4','4']);
Aliday K
  • 141
  • 1
  • 3
8

For integer arrays use intarray extension:

create extension if not exists intarray;
select cardinality(uniq(string_to_array('1,2,3,4,4', ',')::int[])) as foo

or the function

create or replace function public.array_unique(arr anyarray)
    returns anyarray
    language sql
as $function$
    select array_agg(distinct elem)
    from unnest(arr) as arr(elem) 
$function$;

for any array. You can easily modify the function to preserve the original order of the array elements:

create or replace function public.array_unique_ordered(arr anyarray)
    returns anyarray
    language sql
as $function$
    select array_agg(elem order by ord)
    from (
        select distinct on(elem) elem, ord
        from unnest(arr) with ordinality as arr(elem, ord)
        order by elem, ord
        ) s
$function$;

Example:

with my_data(arr) as (values ('{d,d,a,c,b,b,a,c}'::text[]))
select array_unique(arr), array_unique_ordered(arr)
from my_data

 array_unique | array_unique_ordered
--------------+----------------------
 {a,b,c,d}    | {d,a,c,b}
(1 row)
klin
  • 112,967
  • 15
  • 204
  • 232
1

Going off of @klin's accepted answer, I modified it to remove nulls in the process of choosing only the distinct values.

create or replace function public.array_unique_no_nulls(arr anyarray)
returns anyarray
language sql
as $function$
select array_agg(distinct a)
from (
    select unnest(arr) a 
) alias
where a is not null
$function$;
stevevance
  • 381
  • 4
  • 10