3
$\begingroup$
lis={"#49:5"->"#61:7", "#49:5"->"#62:5", "#49:6"->"#61:8", "#49:6"->"#62:4", "#49:7"->"#61:10", "#49:7"->"#62:3", "#49:8"->"#61:9", "#49:8"->"#62:6"}

I would like to partition this list of rules into a number of sublists that is based on value string patterns #61:x, #62:y,.... #6n:z

clusters=Flatten@DeleteDuplicates@StringCases[Values@mrules,"#"~~cluster__~~":"->cluster]

Out= {61,62}

Therefore this list of rules can be split into two sublists (ordering is not required here):

 {{"#49:5"->"#61:7", "#49:6"->"#61:8", "#49:7"->"#61:10", "#49:8"->"#61:9"}, {"#49:5"->"#62:5", "#49:6"->"#62:4", "#49:7"->"#62:3", "#49:8"->"#62:6"}}

I can also take the list of values sorted

Sort@Values@lis

Out = {"#61:10", "#61:7", "#61:8", "#61:9", "#62:3", "#62:4", "#62:5", "#62:6"}

Then I experimented with Cases, Split, Select, StringMatchQ, etc without any luck.

Could you please assist me with this problem ?

$\endgroup$
8
$\begingroup$

One way:

label[_ -> s_] := StringReplace[s, "#" ~~ n__ ~~ ":" ~~ __ :> n]
GatherBy[lis, label]

(* Out: {{"#49:5" -> "#61:7", "#49:6" -> "#61:8", "#49:7" -> "#61:10", 
  "#49:8" -> "#61:9"}, {"#49:5" -> "#62:5", "#49:6" -> "#62:4", 
  "#49:7" -> "#62:3", "#49:8" -> "#62:6"}} *)
$\endgroup$
  • $\begingroup$ A very clever and elegant solution indeed, thank you C.E. $\endgroup$ – Athanassios May 31 '16 at 1:44
  • $\begingroup$ For those who want to avoid ToExpression[]: GatherBy[lis, StringCases[Last[#], "#" ~~ d : DigitCharacter .. ~~ __ :> d] &] $\endgroup$ – J. M. will be back soon May 31 '16 at 10:44
  • $\begingroup$ @J.M. You posting this made me realize that ToExpression was superfluous in the first place, because they're just labels. They're not used for anything other than checking for equality. So I removed it in the answer. $\endgroup$ – C. E. May 31 '16 at 12:05
5
$\begingroup$

Just for another approach (based on grouping by "#6n". Using GroupBy:

lis = {"#49:5" -> "#61:7", "#49:5" -> "#62:5", "#49:6" -> "#61:8", 
   "#49:6" -> "#62:4", "#49:7" -> "#61:10", "#49:7" -> "#62:3", 
   "#49:8" -> "#61:9", "#49:8" -> "#62:6"};
gp = GroupBy[lis, StringTake[#[[2]], {2, 3}] &, Rule @@@ # &];
v = Values[gp]

To sort by rule value:

f = ToExpression[StringSplit[StringDrop[#, 1], ":"]] &;
SortBy[#, f@#[[2]] &] & /@ v

yields:

{{"#49:5" -> "#61:7", "#49:6" -> "#61:8", "#49:8" -> "#61:9",
"#49:7" -> "#61:10"}, {"#49:7" -> "#62:3", "#49:6" -> "#62:4",
"#49:5" -> "#62:5", "#49:8" -> "#62:6"}}

$\endgroup$
  • $\begingroup$ Thank you, always eager to learn new things ;-) $\endgroup$ – Athanassios May 31 '16 at 6:00
  • $\begingroup$ @Athanassios Παρακαλώ. I voted for C.E. I just wanted to show another way. Mma is versatile. I learn a lot from the creativity of the users on this site myself. :) $\endgroup$ – ubpdqn May 31 '16 at 6:04
  • $\begingroup$ Hi, I studied a bit your code. I noticed that the third argument of GroupBy, i.e. (Rule @@@ # &) can be omitted ??? And I am trying hard to understand this SortBy. Would you be kind enough to provide some analysis, e.g. rewrite it in a more comprehensible way. This f@#[[2]]& is really too difficult to grasp. Thank you $\endgroup$ – Athanassios Jun 4 '16 at 8:51
  • $\begingroup$ I can see that : f /@ Values /@ Values@gp {{{61, 7}, {61, 8}, {61, 10}, {61, 9}}, {{62, 5}, {62, 4}, {62, 3}, {62, 6}}} But I cannot understand how this f@#[[2]]& is applied on Values@gp $\endgroup$ – Athanassios Jun 4 '16 at 8:57
  • $\begingroup$ @Athanassios f@#[[2]& is just using the function fon the second part of the argument. In this case the second argument is the value of the rule. The value is a string (a pair of numbers separate by ':'). f converts this into an expression (numerical) that SortBy can use to order. I hope this is clearer. # is just a placeholder and & is used for completion pure functions.:) $\endgroup$ – ubpdqn Jun 4 '16 at 8:57

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.