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$

3 Answers 3

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$
3
  • $\begingroup$ A very clever and elegant solution indeed, thank you C.E. $\endgroup$ May 31, 2016 at 1:44
  • $\begingroup$ For those who want to avoid ToExpression[]: GatherBy[lis, StringCases[Last[#], "#" ~~ d : DigitCharacter .. ~~ __ :> d] &] $\endgroup$ May 31, 2016 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, 2016 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$
8
  • $\begingroup$ Thank you, always eager to learn new things ;-) $\endgroup$ May 31, 2016 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, 2016 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$ Jun 4, 2016 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$ Jun 4, 2016 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, 2016 at 8:57
1
$\begingroup$
Clear["Global`*"]
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"}


GatherBy[lis, StringTake[Values@#, {2, 3}] &]

or

GatherBy[lis, First@StringCases[#, NumberString] &@*Values]

Result

{{"#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$

Your Answer

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

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