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$
    – Lacia
    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$ Aug 8, 2023 at 14:25
  • $\begingroup$ Which is the fastest? $\endgroup$
    – user5601
    Aug 10, 2023 at 2:14
  • $\begingroup$ @user5610: some speed test results are given below (see @Lacia). $\endgroup$ Aug 10, 2023 at 2:42

5 Answers 5

8
$\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$
    – ubpdqn
    Aug 9, 2023 at 3:39
3
$\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$
2
$\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$
2
$\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$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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