# Extract the paired samples from a listing of all samples

I am comparing genomic profiles of identical samples and I need to extract the paired samples from a listing of all samples, so as an illustration how can I adapt "How can I get list of duplicates...." to this problem of keeping only lists that have duplicated samples.

{{sample1,2},{sample1,3},{sample2,3},{sample3,4},{sample3,6}}

=>

{{sample1,2},{sample1,3},{sample3,4},{sample3,6}}

On my machine, the following

F[list_] := Flatten[Select[Gather[list, First[#1] == First[#2] &], Length[#] > 1 &], 1]


is faster than

G[list_] := Flatten[Cases[GroupBy[list, First], {_, __}], 1]


although I am not entirely sure why: I suspect it has to do with pattern matching being slower. When the number of unpaired samples is large, the evaluation time discrepancy increases.

• Kuba's use of GroupBy was unnecessary and counterproductive. I corrected his answer to use GatherBy instead and it is now much faster. Feb 7, 2017 at 18:53
list = {{sample1, 2}, {sample1, 3}, {sample2, 3}, {sample3,
4}, {sample3, 6}}


Flatten[Cases[GatherBy[list, First], {_, __}], 1]

{{sample1, 2}, {sample1, 3}, {sample3, 4}, {sample3, 6}}


So for

list = {{sample1, 1}, {sample2, 1}}


we will get

{}


as there are no duplicates in sample*.

• Much more elegant than what I had in the mean time Select[list, Count[Flatten@list, First@#] > 1 &] Feb 7, 2017 at 12:06
• @Feyre A matter of preference I suppose ;)
– Kuba
Feb 7, 2017 at 12:09
• As of 10.0, there's Catenate for Flatten[..., 1]. Feb 7, 2017 at 13:24
• @MartinEnder and Join @@ is sometimes faster than either, e.g. if the input list is a packed array in this case, so it is still often my first choice. Feb 7, 2017 at 18:58
• @Mr.Wizard I used GroupBy, I could have bet it wasn't the case. Thanks for correction of that typo :)
– Kuba
Feb 7, 2017 at 19:02

I recommend using DeleteDuplicatesBy for this task.

data = {{sample1, 2}, {sample1, 3}, {sample2, 3}, {sample3, 4}, {sample3, 6}};
DeleteDuplicatesBy[data, Last]


{{sample1, 2}, {sample1, 3}, {sample3, 4}, {sample3, 6}}

• I think OP picked unfortunate example because the point is to keep entries which appear more than once base on the first element. So {{sample1,1},{sample2,1}} shoul be left empty while your method will give {{sample1,1}}
– Kuba
Feb 7, 2017 at 12:01
• @Kuba. I think you're right. Feb 8, 2017 at 1:16
list = {{sample1, 2}, {sample1, 3}, {sample2, 3}, {sample3, 4}, {sample3, 6}};


Using SequenceSplit (new in 11.3)

SequenceSplit[list, {a : {_, b_}, {_, b_} ...} :> a]


{{sample1, 2}, {sample1, 3}, {sample3, 4}, {sample3, 6}}