I have a large list of 2-tuples and I need a function that lists first values that have at least one repeated second value. Small example:

   {"name11",4},{"name6",-3},{"name15",4.1}] =

How to do it efficiently?


Here's one way to solve your problem. First, let

list1 = {{"name1",4},{"name2",5.4},{"name7",4},{"name9",-3},{"name11",4},


Sort[Transpose[Catenate[Select[GatherBy[list1, Last], Length[#] > 1 &]]][[1]]]

I don't know if that is efficient enough for you, but will be interested to see how it compares with other proposed solutions.

  • $\begingroup$ Thank You, your solution runs the fastest among others. $\endgroup$ – old Jul 5 at 9:13
list = {{"name1", 4}, {"name2", 5.4}, {"name7", 4}, {"name9", -3}, {"name11", 4},
     {"name6", -3}, {"name15", 4.1}};

You can also use Counts and Cases:

counts = Counts[list[[All, 2]]];
Cases[{a_, _?(counts[#] > 1 &)} :> a] @ list

{"name1", "name7", "name9", "name11", "name6"}

And an alternative way to use GatherBy + Select combination:

list[[Join @@ 
  Select[Length @ # > 1 &] @
    GatherBy[Range @ Length @ list, list[[#, 2]] &], 1]]

{"name1", "name7", "name11", "name9", "name6"}


Applying GroupBy to your test list:

GroupBy[testlist, Last -> First]

<|4 -> {"name1", "name7", "name11"}, 5.4 -> {"name2"}, -3 -> {"name9", "name6"}, 4.1 -> {"name15"}|>

It remains to select values with the length larger than one. This can be done, for example like this:

func2[l_] := Flatten[Values[Select[GroupBy[l, Last->First], (Length[#]>1)&]]]


{"name1", "name7", "name11", "name9", "name6"}

Same concept as a composition of functions:

func = Flatten@*Values@*Select[GreaterThan[1]@*Length]@*GroupBy[Last->First]

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.