6
$\begingroup$

I have two lists: list1 and list2:

list1 = {{"TSC" \[DirectedEdge] "FIN", 22}, {"CO12" \[DirectedEdge] "AGF", 21}, {"MA2" \[DirectedEdge] "EGW", 20}, {"MA1" \[DirectedEdge] "FIN", 19}, {"FIN" \[DirectedEdge] "CO12", 18}, {"EGW" \[DirectedEdge] "TSC", 17}, {"FIN" \[DirectedEdge] "MA2", 16}, {"CO12" \[DirectedEdge] "MA1", 14}, {"AGF" \[DirectedEdge] "MA2", 13}, {"MA2" \[DirectedEdge] "AGF", 12}, {"AGF" \[DirectedEdge] "CO12", 11}, {"CST" \[DirectedEdge] "MA2", 10}, {"EST" \[DirectedEdge] "CO12", 9}, {"MA2" \[DirectedEdge] "CST", 8}, {"FIN" \[DirectedEdge] "TSC", 7}, {"EST" \[DirectedEdge] "MA1", 6}, {"EGW" \[DirectedEdge] "CST", 5}, {"CST" \[DirectedEdge] "EGW", 4}, {"AGF" \[DirectedEdge] "CST", 2}}; list2 = {"MA2" \[DirectedEdge] "AGF", "AGF" \[DirectedEdge] "MA2", "AGF" \[DirectedEdge] "CST", "FIN" \[DirectedEdge] "CO12", "MA1" \[DirectedEdge] "FIN", "FIN" \[DirectedEdge] "MA2", "EGW" \[DirectedEdge] "TSC"}; 

I want to select those {x, y} pairs from list1 using elements (x) in list2, and then take the average of the ys that are already selected. I like to do it in one-liner code.

I tried:

Mean[Select[list1, MemberQ[#, list2] &][[All,2]]] 

with no success. I tried many other codes available in this forum but I cannot get what I want.

$\endgroup$
4
  • 3
    $\begingroup$ Select[list1,MemberQ[list2,#[[1]]]&][[All,2]] $\endgroup$ Commented Aug 8, 2023 at 14:14
  • $\begingroup$ @Lacia:Many thanks for the code. This solved my problem!!! If you put it as an answer, I will accept it. $\endgroup$ Commented Aug 8, 2023 at 14:25
  • $\begingroup$ Which is the fastest? $\endgroup$ Commented Aug 10, 2023 at 2:14
  • $\begingroup$ @user5610: some speed test results are given below (see @Lacia). $\endgroup$ Commented Aug 10, 2023 at 2:42

6 Answers 6

9
$\begingroup$

As shown by other answers, there are many solutions for one problem in Mathematica.

List

MemberQ

Select[list1,MemberQ[list2,#[[1]]]&][[All,2]]//RepeatedTiming (*{0.0000154381,{19,18,17,16,13,12,2}}*) Cases[list1,{edge_,int_}/;MemberQ[list2,edge]:>int]//RepeatedTiming (*{0.0000130373,{19,18,17,16,13,12,2}}*) 

Alternatives is faster since it's purely a pattern

Cases[list1,{Alternatives@@list2,int_}:>int]//RepeatedTiming (*{5.47926·10^-6,{19,18,17,16,13,12,2}}*) 

Set

Intersection has an option SameTest. The effect is that Intersection[A,B,SameTest->f] returns the intersection of A by B according to f

Intersection[list1,list2,SameTest->(First[#1]===#2&)][[All,2]]//RepeatedTiming (*{0.000107458,{2,13,17,18,16,19,12}}*) 

Notice that Intersection is a set-theoretical function, hence it breaks the original order and is slower.

Association

This is realized by @Syed. In my experience, this approach is more suitable when dealing with dataset.

  • The code is more readable/maintainable. If querying the data with more complicated requirements, the level specification in the list/set approach is much harder to track (imagine that there are lots of [[All,1;;-1;;2]]... )

  • Association has better performance than List, see e.g. How to make use of Associations?

  • support SQL-like operations, see guide/DatabaseLikeOperationsOnDatasets

For simple tasks there seems no significant difference between these two approaches.

$\endgroup$
5
$\begingroup$
result = Rule @@@ list1 // KeyTake[list2] // Values 

{12, 13, 2, 18, 19, 16, 17}

result // Mean 

97/7

$\endgroup$
1
  • 2
    $\begingroup$ Mean[list2 /. Rule @@@ list1] suffices $\endgroup$ Commented Aug 9, 2023 at 3:39
4
$\begingroup$

Using KeySelect:

asc1 = (First@# -> Last@#) & /@ list1 Values@KeySelect[asc1, MemberQ[list2, #] &] 

{19, 18, 17, 16, 13, 12, 2}

To get the mean:

Mean@Values@KeySelect[asc1, MemberQ[list2, #] &] 

Using Position and Extract:

Extract[list1 , Position[ Position[list2, #] & /@ list1[[All, 1]] , Except[{}], 1, Heads -> False] ] // Map[Last] // Mean 
$\endgroup$
3
$\begingroup$

Try this:

f[rule_] := Map[If[MemberQ[#, rule], #, Nothing] &, list1]; lst = Flatten[Map[f[#] &, list2], 1] (* {{"MA2" \[DirectedEdge] "AGF", 12}, {"AGF" \[DirectedEdge] "MA2", 13}, {"AGF" \[DirectedEdge] "CST", 2}, {"FIN" \[DirectedEdge] "CO12", 18}, {"MA1" \[DirectedEdge] "FIN", 19}, {"FIN" \[DirectedEdge] "MA2", 16}, {"EGW" \[DirectedEdge] "TSC", 17}} *) Mean[Transpose[lst][[2]]] (* 97/7 *) 

Have fun!

$\endgroup$
3
$\begingroup$
Extract[list1[[All,2]],Position[list1[[All,1]],Alternatives@@list2]]//Mean (* 97/7 *) 

Perhaps a more readable version:

 Extract[list1,Position[list1,Alternatives@@list2].{{1,0},{0,2}}]//Mean (* 97/7 *) 

Or, usingPart rather than Extract:

list1[[All,2]][[(list1//Position[Alternatives@@list2])[[All,1]]]]//Mean (* 97/7 *) 
$\endgroup$
2
$\begingroup$

"Using Select with ContainsAny

Last /@ Select[list1, ContainsAny @ list2] 

{19, 18, 17, 16, 13, 12, 2}

Using Cases with Alternatives

Cases[list1, {Alternatives @@ list2, a_} :> a] 

{19, 18, 17, 16, 13, 12, 2}

$\endgroup$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.