ASKSAGE: Sage Q&A Forum - Individual question feedhttps://ask.sagemath.org/questions/Q&A Forum for SageenCopyright Sage, 2010. Some rights reserved under creative commons license.Fri, 02 Nov 2012 22:48:55 -0500Gathering sublists based on functional programming (GatherBy)https://ask.sagemath.org/question/9495/gathering-sublists-based-on-functional-programming-gatherby/Hi,
I'm looking at translating a very nice solution to the MrP and MrS puzzle.
http://mathematica.stackexchange.com/questions/13898/how-to-improve-this-code-for-solving-the-mr-s-and-mr-p-puzzle
The translation of the problem involves list comprehensions and functional programming. We can generate the tuples of solutions in the form:
possibilities = [ (i,j) for i in range(2,99) for j in range(2,i)]
Then we would like to group these possibilities into lists that have multiple factorizations...
In this case informationFilter could be a lambda function for mrP:
mrP = lambda a,b : a*b
I am having trouble finding an easy way to do the equivalent of the mathematica function: GatherBy:
GatherBy[possibilities, informationFilter]
So the question is: Given a list of tuples like :
[(3, 2), (4, 2), (4, 3), (5, 2), (5, 3), (5, 4), (6, 2), (6, 3), (6, 4), (6, 5)... (98,97)]
How would you gather them into sublists such that their products are the same...
[(4,3),(6,2)] would be one valid sublist.
Many thanks for letting me "think out loud" on this one. Apologies in advance if the answer is trivial.
./patFri, 02 Nov 2012 06:13:50 -0500https://ask.sagemath.org/question/9495/gathering-sublists-based-on-functional-programming-gatherby/Answer by Jesustc for <p>Hi,
I'm looking at translating a very nice solution to the MrP and MrS puzzle.
<a href="http://mathematica.stackexchange.com/questions/13898/how-to-improve-this-code-for-solving-the-mr-s-and-mr-p-puzzle">http://mathematica.stackexchange.com/...</a></p>
<p>The translation of the problem involves list comprehensions and functional programming. We can generate the tuples of solutions in the form:</p>
<p>possibilities = [ (i,j) for i in range(2,99) for j in range(2,i)]</p>
<p>Then we would like to group these possibilities into lists that have multiple factorizations...
In this case informationFilter could be a lambda function for mrP:
mrP = lambda a,b : a*b</p>
<p>I am having trouble finding an easy way to do the equivalent of the mathematica function: GatherBy:</p>
<p>GatherBy[possibilities, informationFilter]</p>
<p>So the question is: Given a list of tuples like :
[(3, 2), (4, 2), (4, 3), (5, 2), (5, 3), (5, 4), (6, 2), (6, 3), (6, 4), (6, 5)... (98,97)]</p>
<p>How would you gather them into sublists such that their products are the same...</p>
<p>[(4,3),(6,2)] would be one valid sublist.</p>
<p>Many thanks for letting me "think out loud" on this one. Apologies in advance if the answer is trivial.</p>
<p>./pat</p>
https://ask.sagemath.org/question/9495/gathering-sublists-based-on-functional-programming-gatherby/?answer=14221#post-id-14221How about
sage: initial_list = [(3, 2), (4, 2), (4, 3), (5, 2), (5, 3),\
sage: (5, 4), (6, 2), (6, 3), (6, 4), (6, 5), (98,97)]
sage: sublists = []
sage: for product in list(set([a*b for a,b in initial_list])) :
sage: sublists.append([pair for pair in initial_list if pair[0]*pair[1] == product])
Or, maybe, as a dictionary, with the products as keys:
sage: initial_list = [(3, 2), (4, 2), (4, 3), (5, 2), (5, 3),\
sage: (5, 4), (6, 2), (6, 3), (6, 4), (6, 5), (98,97)]
sage: products = list(set([a*b for a,b in initial_list]))
sage: sublists = dict([[product,[]] for product in products])
sage: for pair in initial_list :
sage: product = pair[0]*pair[1]
sage: sublists[product].append(pair)
EDIT:
Slightly faster method (only multiplying once):
sage: initial_list = [(3, 2), (4, 2), (4, 3), (5, 2), (5, 3),\
sage: (5, 4), (6, 2), (6, 3), (6, 4), (6, 5), (98,97)]
sage: sublists = dict()
sage: for pair in initial_list :
sage: product = pair[0]*pair[1]
sage: if not(product in sublists.keys()) :
sage: sublists[product] = []
sage: sublists[product].append(pair)
EDIT:
Even in a single line :)
sage: sublists = dict([[product,[pair for pair in initial_list if pair[0]*pair[1] == product]] for product in list(set([a*b for a,b in initial_list]))])
Yeah, I am having fun!Fri, 02 Nov 2012 06:30:46 -0500https://ask.sagemath.org/question/9495/gathering-sublists-based-on-functional-programming-gatherby/?answer=14221#post-id-14221Comment by PatB for <p>How about</p>
<pre><code>sage: initial_list = [(3, 2), (4, 2), (4, 3), (5, 2), (5, 3),\
sage: (5, 4), (6, 2), (6, 3), (6, 4), (6, 5), (98,97)]
sage: sublists = []
sage: for product in list(set([a*b for a,b in initial_list])) :
sage: sublists.append([pair for pair in initial_list if pair[0]*pair[1] == product])
</code></pre>
<p>Or, maybe, as a dictionary, with the products as keys:</p>
<pre><code>sage: initial_list = [(3, 2), (4, 2), (4, 3), (5, 2), (5, 3),\
sage: (5, 4), (6, 2), (6, 3), (6, 4), (6, 5), (98,97)]
sage: products = list(set([a*b for a,b in initial_list]))
sage: sublists = dict([[product,[]] for product in products])
sage: for pair in initial_list :
sage: product = pair[0]*pair[1]
sage: sublists[product].append(pair)
</code></pre>
<p>EDIT:</p>
<p>Slightly faster method (only multiplying once):</p>
<pre><code>sage: initial_list = [(3, 2), (4, 2), (4, 3), (5, 2), (5, 3),\
sage: (5, 4), (6, 2), (6, 3), (6, 4), (6, 5), (98,97)]
sage: sublists = dict()
sage: for pair in initial_list :
sage: product = pair[0]*pair[1]
sage: if not(product in sublists.keys()) :
sage: sublists[product] = []
sage: sublists[product].append(pair)
</code></pre>
<p>EDIT:</p>
<p>Even in a single line :)</p>
<pre><code>sage: sublists = dict([[product,[pair for pair in initial_list if pair[0]*pair[1] == product]] for product in list(set([a*b for a,b in initial_list]))])
</code></pre>
<p>Yeah, I am having fun!</p>
https://ask.sagemath.org/question/9495/gathering-sublists-based-on-functional-programming-gatherby/?comment=18758#post-id-18758Hi Jesustc,
I thought about the answer and came up with the 2nd approach, using the hash (perl speak)
Interestingly, unlike sage/python, perl requires that the hash have a pointer (reference) to a list because perl does not natively supply objects. I am glad I'm switching to python!Fri, 02 Nov 2012 17:07:49 -0500https://ask.sagemath.org/question/9495/gathering-sublists-based-on-functional-programming-gatherby/?comment=18758#post-id-18758Comment by Jesustc for <p>How about</p>
<pre><code>sage: initial_list = [(3, 2), (4, 2), (4, 3), (5, 2), (5, 3),\
sage: (5, 4), (6, 2), (6, 3), (6, 4), (6, 5), (98,97)]
sage: sublists = []
sage: for product in list(set([a*b for a,b in initial_list])) :
sage: sublists.append([pair for pair in initial_list if pair[0]*pair[1] == product])
</code></pre>
<p>Or, maybe, as a dictionary, with the products as keys:</p>
<pre><code>sage: initial_list = [(3, 2), (4, 2), (4, 3), (5, 2), (5, 3),\
sage: (5, 4), (6, 2), (6, 3), (6, 4), (6, 5), (98,97)]
sage: products = list(set([a*b for a,b in initial_list]))
sage: sublists = dict([[product,[]] for product in products])
sage: for pair in initial_list :
sage: product = pair[0]*pair[1]
sage: sublists[product].append(pair)
</code></pre>
<p>EDIT:</p>
<p>Slightly faster method (only multiplying once):</p>
<pre><code>sage: initial_list = [(3, 2), (4, 2), (4, 3), (5, 2), (5, 3),\
sage: (5, 4), (6, 2), (6, 3), (6, 4), (6, 5), (98,97)]
sage: sublists = dict()
sage: for pair in initial_list :
sage: product = pair[0]*pair[1]
sage: if not(product in sublists.keys()) :
sage: sublists[product] = []
sage: sublists[product].append(pair)
</code></pre>
<p>EDIT:</p>
<p>Even in a single line :)</p>
<pre><code>sage: sublists = dict([[product,[pair for pair in initial_list if pair[0]*pair[1] == product]] for product in list(set([a*b for a,b in initial_list]))])
</code></pre>
<p>Yeah, I am having fun!</p>
https://ask.sagemath.org/question/9495/gathering-sublists-based-on-functional-programming-gatherby/?comment=18756#post-id-18756Python is definitely fun! Though the solution of Jason Grout is definitely better (and probably more efficient too, I have not tested it), if one does not know the specific module to do it at best, it is easy to come up with a few possible solutions and to quickly prototype them :).Fri, 02 Nov 2012 22:48:55 -0500https://ask.sagemath.org/question/9495/gathering-sublists-based-on-functional-programming-gatherby/?comment=18756#post-id-18756Answer by Jason Grout for <p>Hi,
I'm looking at translating a very nice solution to the MrP and MrS puzzle.
<a href="http://mathematica.stackexchange.com/questions/13898/how-to-improve-this-code-for-solving-the-mr-s-and-mr-p-puzzle">http://mathematica.stackexchange.com/...</a></p>
<p>The translation of the problem involves list comprehensions and functional programming. We can generate the tuples of solutions in the form:</p>
<p>possibilities = [ (i,j) for i in range(2,99) for j in range(2,i)]</p>
<p>Then we would like to group these possibilities into lists that have multiple factorizations...
In this case informationFilter could be a lambda function for mrP:
mrP = lambda a,b : a*b</p>
<p>I am having trouble finding an easy way to do the equivalent of the mathematica function: GatherBy:</p>
<p>GatherBy[possibilities, informationFilter]</p>
<p>So the question is: Given a list of tuples like :
[(3, 2), (4, 2), (4, 3), (5, 2), (5, 3), (5, 4), (6, 2), (6, 3), (6, 4), (6, 5)... (98,97)]</p>
<p>How would you gather them into sublists such that their products are the same...</p>
<p>[(4,3),(6,2)] would be one valid sublist.</p>
<p>Many thanks for letting me "think out loud" on this one. Apologies in advance if the answer is trivial.</p>
<p>./pat</p>
https://ask.sagemath.org/question/9495/gathering-sublists-based-on-functional-programming-gatherby/?answer=14223#post-id-14223How about using the [groupby](http://docs.python.org/2/library/itertools.html#itertools.groupby) function?
a=[(3, 2), (4, 2), (4, 3), (5, 2), (5, 3), (5, 4), (6, 2), (6, 3), (6, 4), (6, 5), (98,97)]
from itertools import groupby
print [list(g) for k,g in groupby(sorted(a,key=prod),key=prod)]
print dict([(k,list(g)) for k,g in groupby(sorted(a,key=prod),key=prod)])
http://aleph.sagemath.org/?q=5e10542b-adb9-4c06-8527-98f9b8907469&lang=sageFri, 02 Nov 2012 13:12:34 -0500https://ask.sagemath.org/question/9495/gathering-sublists-based-on-functional-programming-gatherby/?answer=14223#post-id-14223Comment by benjaminfjones for <p>How about using the <a href="http://docs.python.org/2/library/itertools.html#itertools.groupby">groupby</a> function?</p>
<pre><code>a=[(3, 2), (4, 2), (4, 3), (5, 2), (5, 3), (5, 4), (6, 2), (6, 3), (6, 4), (6, 5), (98,97)]
from itertools import groupby
print [list(g) for k,g in groupby(sorted(a,key=prod),key=prod)]
print dict([(k,list(g)) for k,g in groupby(sorted(a,key=prod),key=prod)])
</code></pre>
<p><a href="http://aleph.sagemath.org/?q=5e10542b-adb9-4c06-8527-98f9b8907469&lang=sage">http://aleph.sagemath.org/?q=5e10542b...</a></p>
https://ask.sagemath.org/question/9495/gathering-sublists-based-on-functional-programming-gatherby/?comment=18759#post-id-18759+1 for groupby (more FP)Fri, 02 Nov 2012 16:04:27 -0500https://ask.sagemath.org/question/9495/gathering-sublists-based-on-functional-programming-gatherby/?comment=18759#post-id-18759Comment by PatB for <p>How about using the <a href="http://docs.python.org/2/library/itertools.html#itertools.groupby">groupby</a> function?</p>
<pre><code>a=[(3, 2), (4, 2), (4, 3), (5, 2), (5, 3), (5, 4), (6, 2), (6, 3), (6, 4), (6, 5), (98,97)]
from itertools import groupby
print [list(g) for k,g in groupby(sorted(a,key=prod),key=prod)]
print dict([(k,list(g)) for k,g in groupby(sorted(a,key=prod),key=prod)])
</code></pre>
<p><a href="http://aleph.sagemath.org/?q=5e10542b-adb9-4c06-8527-98f9b8907469&lang=sage">http://aleph.sagemath.org/?q=5e10542b...</a></p>
https://ask.sagemath.org/question/9495/gathering-sublists-based-on-functional-programming-gatherby/?comment=18757#post-id-18757Thanks for posting this solution as well, illustrating the sagesse that can be found when one looks to find equivalents.Fri, 02 Nov 2012 17:16:16 -0500https://ask.sagemath.org/question/9495/gathering-sublists-based-on-functional-programming-gatherby/?comment=18757#post-id-18757