Search code examples
arraysduplicateszsh

zsh - print array duplicates ONLY


Not trying to blindly remove duplicates from an array.

I want to print out any duplicate values a given array might have.

When I use this command:

printf '%s\n' "${arr[@]}" | awk '!($0 in seen){seen[$0];print $0}'

...it prints out all unique values, and leaves the duplicates out.

Expected this to do the opposite, but get no results:

printf '%s\n' "${arr[@]}" | awk '($0 in seen){seen[$0];print $0}'

Sample Input:

arr=(1 2 2 3)

Expected Output:

2

EDIT

Right now, this seems to be working. Leaving it open for a day or so in case someone has a better way...

array=($arr)
for value in ${array[@]}; do
    [[ $(grep "${value}" $(echo ${(F)arr} | wc -l) -gt 1 ]] && echo $value;
done

Solution

  • Very short: just print the value when the count is exactly 1 (which occurs on the first duplicate you see):

    % print -l $arr | awk 'a[$0]++ == 1'
    

    You can do something similar in pure zsh:

    % () { local -A a; for x; do ((a[$x]++ == 1)) && print $x; done } $arr
    2
    

    The anonymous function is simply used to localize the use of the array a. An associative array is used to accommodate arrays of any values, not just integer values.

    Slightly shorter, using an short form of for:

    % () { local -A a; for x; { ((a[$x]++ == 1)) && print $x } } $arr