7

I am trying to find a neat way of applying an operation to each list element, but do not know how to properly use multiple slots or whether it is actually possible to solve this with multiple slots. I am doing the following thing:

I have defined the following objects:

assoc1 = <|{a, b} -> 5, {c, d} -> 2,  {e, f} -> -3|>;
lyst1 = {b, e, g};
lyst2 = {{b, e, g}, {a, b, c}}; 

Now, I want to select all entries in assoc1 whose key lists have a nonzero intersection with lyst1. This I can do in the following way:

KeySelect[assoc1, Intersection[lyst1, #] =!= {} &]

correctly getting the return:

<|{a, b} -> 5, {e, f} -> -3|>

And now the problem: Is there a way to elegantly do this for each list in lyst2 ? I know I could just use a for loop, but I was hoping for something shorter. I generally know how to apply a function to each element in lyst2 via "/@", but for that I would usually put a second Slot (=#) inside the Intersection function at the place where you see "lyst1" in my working example. I mean something like (knowing that this exact line does NOT do what I want):

KeySelect[assoc1, Intersection[#2, #1] =!= {} &] &/@ lyst2

where "#1" is the slot for each element in assoc1 whose key I am testing and "#2" is the slot used for looping over lyst2.

I do not know how to circumvent that or make it work with this second slot and would be very grateful for any suggestion!

  • 2
    Try f[v_]:=KeySelect[assoc1, Intersection[v, #] =!= {} &] and then Map[f[#]&,lyst2] or f/@lyst2 and see if either of those are acceptable – Bill Mar 16 '23 at 19:06
  • Of course it is! Thank you very much! I tried so much more complicated stuff and completely overlooked that by defining a function in this way there is no problem! If it is ok, I would leave the question open out of curiosity to see if there are other neat ideas like yours. But nevertheless, you should definitely post this not only as a comment but as an answer! – michelangelov Mar 16 '23 at 19:11
  • 1
    Related: 38393. – Syed Mar 16 '23 at 19:26
  • Thanks @Syed, I was not familiar with "OperatorApplied/Curry". – michelangelov Mar 16 '23 at 19:52

4 Answers4

6

As requested, Use function definition to separate the two applications of #

f[v_]:=KeySelect[assoc1, Intersection[v, #] =!= {} &]
Map[f[#]&,lyst2] (*or f/@lyst2 *)
Bill
  • 12,001
  • 12
  • 13
  • 1
    Try the following so that your function applies to each list: f[v_?VectorQ] := KeySelect[assoc1, Intersection[v, #] =!= {} &]; f[v_?TensorQ] := Map[f[#] &, v];` – E. Chan-López Mar 16 '23 at 19:29
6

Try also this:

g[lst_List] := Intersection[lst, #] != {} &;
KeySelect[assoc1, g[#]] & /@ lyst2

(* {<|{a, b} -> 5, {e, f} -> -3|>, <|{a, b} -> 5, {c, d} -> 2|>} *)

Have fun!

Alexei Boulbitch
  • 39,397
  • 2
  • 47
  • 96
5

An alternative to the function that @Bill created for applying to more complex arrays is as follows:

f[v_?VectorQ] := KeySelect[assoc1, Intersection[v, #] =!= {} &]
f[v_?TensorQ] := Map[f[#] &, v]

Test:

f@lyst1
(*<|{a, b} -> 5, {e, f} -> -3|>*)
f@lyst2
(*{<|{a, b} -> 5, {e, f} -> -3|>, <|{a, b} -> 5, {c, d} -> 2|>}*)
E. Chan-López
  • 23,117
  • 3
  • 21
  • 44
1
asc = <|{a, b} -> 5, {c, d} -> 2, {e, f} -> -3|>;

kv = {b, e, g};

km = {{b, e, g}, {a, b, c}};

A hash-free variant of E. Chan-López answer using ContainsAny

sel[x_?VectorQ] := KeySelect[asc, ContainsAny @ x]

sel[x_?MatrixQ] := sel /@ x

sel @ kv

<|{a, b} -> 5, {e, f} -> -3|>

sel @ km

{<|{a, b} -> 5, {e, f} -> -3|>, <|{a, b} -> 5, {c, d} -> 2|>}

eldo
  • 67,911
  • 5
  • 60
  • 168