Find max value of tuple with multiple values being the same - python

I have a list of tuples, and I need to find the tuple with the max value on the right side. I also need the program to print out each tuple that has this max value. I have tried using lambda, but that only returns one of the tuples with a max value on the left side. Specifically, I have tried:
max(TotalFriendsList,key=lambda x:x[1])
Which returns (1,3)
This is the list:
[(0, 2),
(1, 3),
(2, 3),
(3, 3),
(4, 2),
(5, 3),
(6, 2),
(7, 2),
(8, 3),
(9, 1)]
This is the output i need:
[(1,3),
(2,3),
(3,3),
(5,3),
(8,3)]
Thanks!

You can keep this fairly compact by getting the highest value, then getting corresponding tuples:
l = [(0, 2),
(1, 3),
(2, 3),
(3, 3),
(4, 2),
(5, 3),
(6, 2),
(7, 2),
(8, 3),
(9, 1)]
# pass a generator expression to `max`
greatest = max(item[1] for item in l)
# "filter" `l`, keeping only tuples that have the greatest value as their second element
result = [item for item in l if item[1] == greatest]
print(result)
# [(1, 3), (2, 3), (3, 3), (5, 3), (8, 3)]

>>> lst = [(0, 2),
... (1, 3),
... (2, 3),
... (3, 3),
... (4, 2),
... (5, 3),
... (6, 2),
... (7, 2),
... (8, 3),
... (9, 1)]
>>> mx = max(lst, key=lambda x: x[1])
>>> filter(lambda x: x[1] == mx[1], lst)
[(1, 3), (2, 3), (3, 3), (5, 3), (8, 3)]

This now, after optimization, goes through the list exactly once:
data = [(0, 2),
(1, 3),
(2, 3),
(3, 3),
(4, 2),
(5, 3),
(6, 2),
(7, 2),
(8, 3),
(9, 1)]
maxVal = -1
result = None
for datum in data:
val = datum[1]
if val > maxVal:
result = [datum]
maxVal = val
elif val == maxVal:
result.append(datum)
print result
print
# and the way he wanted it printed...
print "[" + ",\n".join([str(v) for v in result]) + "]"
Notice that since the first entry contains a "winning tuple", this code doesn't process the losers at all. It just does a few comparisons for them, and comparisons cost almost nothing. So it basically does the bare minimum amount of work of building the result list in a single pass. It wouldn't be so efficient if the first tuple weren't a winner.
Output:
[(1, 3), (2, 3), (3, 3), (5, 3), (8, 3)]
[(1, 3),
(2, 3),
(3, 3),
(5, 3),
(8, 3)]
Only I did just what the guy asked for ;) (tic) - all answers were right on...good perpective on different ways to do the same problem

Related

Iterating through a list/dictionary over and over again with a timestep value

So I have a dictionary:
{0: [[(4, 1), (1, 4)], [(2, 3), (3, 2)], [(4, 2), (2, 4), (1, 3), (3, 1)], [(1, 2), (2, 1), (4, 3), (3, 4)]]}
How do I iterate through the nested list values [(4, 1), (1, 4)], [(2, 3), (3, 2)]... over and over again depending on a initiated count value?
For example: initiated_count_value = 0 would refer to [(4, 1), (1, 4)], while initiated_count_value = 3 would refer to [(1, 2), (2, 1), (4, 3), (3, 4)] but then as the count changes by going up the values of the nested list are still referenced.
For example: initiated count value of 4 would refer back again to [(4, 1), (1, 4)].
Thanks.
To loop the overall list index back to the beginning, you can use the % modulo operator.
d = {
0: [
[(4, 1), (1, 4)],
[(2, 3), (3, 2)],
[(4, 2), (2, 4), (1, 3), (3, 1)],
[(1, 2), (2, 1), (4, 3), (3, 4)],
]
}
for initiated_count_value in range(6):
di = initiated_count_value % len(d[0])
print(d[0][di])
--
[(4, 1), (1, 4)]
[(2, 3), (3, 2)]
[(4, 2), (2, 4), (1, 3), (3, 1)]
[(1, 2), (2, 1), (4, 3), (3, 4)]
[(4, 1), (1, 4)]
[(2, 3), (3, 2)]
You could use a generator which took an initial index and then iterated through the list starting at that index and wrapping around:
def get_list(icv):
l = len(dct[0])
while True:
yield dct[0][icv % l]
icv += 1
You could then do something like:
initiated_count_value = 3
for l in get_list(initiated_count_value):
print(l)
Output:
[(1, 2), (2, 1), (4, 3), (3, 4)]
[(4, 1), (1, 4)]
[(2, 3), (3, 2)]
[(4, 2), (2, 4), (1, 3), (3, 1)]
[(1, 2), (2, 1), (4, 3), (3, 4)]
[(4, 1), (1, 4)]
[(2, 3), (3, 2)]
[(4, 2), (2, 4), (1, 3), (3, 1)]
...
If you don't want the loop to run forever, replace the while True in get_list with something like a for i in range(100) or similar.

Product of coordinates with specific order of iteration

Here's a snippet with a regular itertools.product usage:
from itertools import product
arr = [1,2,3]
pairs = list(product(arr, arr))
# pairs = [(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)]
Now I would like to have these points yielded in an order which can be achieved by sorting the resulting tuples in the following way:
sorted(pairs, key=lambda y:max(y))
# [(1, 1), (1, 2), (2, 1), (2, 2), (1, 3), (2, 3), (3, 1), (3, 2), (3, 3)]
Is there a way for me to input those numbers to itertools.product so it yields the tuples in this order, or do I need to sort the pairs after iterating over the results of itertools.product?
You can probably use your own modified approach to achieve this in one go.
sorted([(x, y) for x in [1, 2, 3] for y in [1, 2, 3]], key=lambda y:max(y))
OUTPUT
[(1, 1), (1, 2), (2, 1), (2, 2), (1, 3), (2, 3), (3, 1), (3, 2), (3, 3)]

find combinations in arbitrarily nested lists under conditions

I want to find possible paths on a finite grid of points. Say, starting point is (x,y). Then next point (m,n) in the path is given by conditions
(m!=x) and (n!=y) ie. I exclude the row and column I was in previously.
n < y ie. I always hop DOWN.
m,n >= 0 ie. all the points are always in first quadrant
Stopping criteria is when a point lies on x axis.
Hence, generate all possible combinations of such 'paths' possible.
Following is what I've tried.
def lisy(x,y):
return [(i,j) for i in range(4,0,-1) for j in range(4,0,-1) if(i!=x and j<y)]
def recurse(x,y):
if (not lisy(x,y)):
return (x,y)
else:
return [(x,y), [recurse(i,j) for i,j in lisy(x,y)]]
OUTPUT:
In [89]: recurse(1,4)
Out[89]:
[(1, 4),
[[(4, 3),
[[(3, 2), [(4, 1), (2, 1), (1, 1)]],
(3, 1),
[(2, 2), [(4, 1), (3, 1), (1, 1)]],
(2, 1),
[(1, 2), [(4, 1), (3, 1), (2, 1)]],
(1, 1)]],
[(4, 2), [(3, 1), (2, 1), (1, 1)]],
(4, 1),
[(3, 3),
[[(4, 2), [(3, 1), (2, 1), (1, 1)]],
(4, 1),
[(2, 2), [(4, 1), (3, 1), (1, 1)]],
(2, 1),
[(1, 2), [(4, 1), (3, 1), (2, 1)]],
(1, 1)]],
[(3, 2), [(4, 1), (2, 1), (1, 1)]],
(3, 1),
[(2, 3),
[[(4, 2), [(3, 1), (2, 1), (1, 1)]],
(4, 1),
[(3, 2), [(4, 1), (2, 1), (1, 1)]],
(3, 1),
[(1, 2), [(4, 1), (3, 1), (2, 1)]],
(1, 1)]],
[(2, 2), [(4, 1), (3, 1), (1, 1)]],
(2, 1)]]
This gives me a nested lists of possible new points from each point.
Can anyone tell me how to process my list obtained from recurse(1,4)?
edit1:
Effectively I hop from a given starting point (in a 4x4 grid [finite]), satisfying the three conditions mentioned until stopping criteria is met, ie. m,n > 0
I clarify the requirements I am working under in the docstring of my generator gridpaths(). Note that I have the horizontal size of the grid as a global variable and the vertical size of the grid is irrelevant, the x-coordinates of path points can be up to but not exceed that global value, and x-coordinates of non-consecutive path points can be equal (though consecutive path points must have different x-coordinates). I changed the name of the routine but kept the arguments as you had them. This version of my code adds the requirement that the y-coordinate of the final point on the path must be 1, and it also is safer in accepting arguments.
This is a generator of lists, so my test code shows how large the generator is then prints all the lists.
def gridpaths(x, y):
"""Generate all paths starting at (x,y) [x and y must be positive
integers] where, if (m,n) is the next point in the path after
(x,y), then m and n are positive integers, m <= xsize [xsize is a
global variable], m != x, and n < y, and so on for all consecutive
path points. The final point in the path must have a y-coordinate
of 1. Paths are yielded in lexicographic order."""
def allgridpaths(x, y, pathsofar):
"""Generate all such paths continuing from pathssofar without
the y == 1 requirement for the final path point."""
newpath = pathsofar + [(x, y)]
yield newpath
for m in range(1, xsize+1):
if m != x:
for n in range(1, y):
for path in allgridpaths(m, n, newpath):
yield path
x, y = max(int(x), 1), max(int(y), 1) # force positive integers
for path in allgridpaths(x, y, []):
# Only yield paths that end at y == 1
if path[-1][1] == 1:
yield path
# global variable: horizontal size of grid
xsize = 4
print(sum(1 for p in gridpaths(1, 4)), 'paths total.')
for p in gridpaths(1, 4):
print(p)
The printout shows that the point (1,4) in a 4x4 grid yields 48 paths. In fact, gridpaths(x, y) will return (xsize - 1) * xsize ** (y - 2) paths, which can grow very quickly. That is why I programmed a generator of lists rather than a list of lists. Let me know if your requirements are different from what I suppose. The printout from that code above is:
48 paths total.
[(1, 4), (2, 1)]
[(1, 4), (2, 2), (1, 1)]
[(1, 4), (2, 2), (3, 1)]
[(1, 4), (2, 2), (4, 1)]
[(1, 4), (2, 3), (1, 1)]
[(1, 4), (2, 3), (1, 2), (2, 1)]
[(1, 4), (2, 3), (1, 2), (3, 1)]
[(1, 4), (2, 3), (1, 2), (4, 1)]
[(1, 4), (2, 3), (3, 1)]
[(1, 4), (2, 3), (3, 2), (1, 1)]
[(1, 4), (2, 3), (3, 2), (2, 1)]
[(1, 4), (2, 3), (3, 2), (4, 1)]
[(1, 4), (2, 3), (4, 1)]
[(1, 4), (2, 3), (4, 2), (1, 1)]
[(1, 4), (2, 3), (4, 2), (2, 1)]
[(1, 4), (2, 3), (4, 2), (3, 1)]
[(1, 4), (3, 1)]
[(1, 4), (3, 2), (1, 1)]
[(1, 4), (3, 2), (2, 1)]
[(1, 4), (3, 2), (4, 1)]
[(1, 4), (3, 3), (1, 1)]
[(1, 4), (3, 3), (1, 2), (2, 1)]
[(1, 4), (3, 3), (1, 2), (3, 1)]
[(1, 4), (3, 3), (1, 2), (4, 1)]
[(1, 4), (3, 3), (2, 1)]
[(1, 4), (3, 3), (2, 2), (1, 1)]
[(1, 4), (3, 3), (2, 2), (3, 1)]
[(1, 4), (3, 3), (2, 2), (4, 1)]
[(1, 4), (3, 3), (4, 1)]
[(1, 4), (3, 3), (4, 2), (1, 1)]
[(1, 4), (3, 3), (4, 2), (2, 1)]
[(1, 4), (3, 3), (4, 2), (3, 1)]
[(1, 4), (4, 1)]
[(1, 4), (4, 2), (1, 1)]
[(1, 4), (4, 2), (2, 1)]
[(1, 4), (4, 2), (3, 1)]
[(1, 4), (4, 3), (1, 1)]
[(1, 4), (4, 3), (1, 2), (2, 1)]
[(1, 4), (4, 3), (1, 2), (3, 1)]
[(1, 4), (4, 3), (1, 2), (4, 1)]
[(1, 4), (4, 3), (2, 1)]
[(1, 4), (4, 3), (2, 2), (1, 1)]
[(1, 4), (4, 3), (2, 2), (3, 1)]
[(1, 4), (4, 3), (2, 2), (4, 1)]
[(1, 4), (4, 3), (3, 1)]
[(1, 4), (4, 3), (3, 2), (1, 1)]
[(1, 4), (4, 3), (3, 2), (2, 1)]
[(1, 4), (4, 3), (3, 2), (4, 1)]

Python implementation of set relations

How would I implement the following using python? I've tried using lambda expressions and a few other methods, but I'm not getting the desired results. Basically, I should receive a set of relations that satisfy the check. I.E they have to be divisible by each other, so {(1,1), (1,2), (1,3),...(6,6)}.
Here's the actual question:
In Python, set a variable say S = {1,2,3,4,5,6}; then do as follows: "List all the ordered pairs in the relation R = {(a,b) : a divides b} on the set {1,2,3,4,5,6}."
you can do it by list comprehension -
S = [1,2,3,4,5,6]
result = [ (x,y) for x in S for y in S if y%x==0]
You can use itertools.product within a list comprehension,and as you want they be divisible by each other you can use the condition i%j==0 or j%i==0 :
>>> from itertools import product
>>> [(i,j) for i,j in product(S,repeat=2) if i%j==0 or j%i==0]
[(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (2, 1), (2, 2), (2, 4), (2, 6), (3, 1), (3, 3), (3, 6), (4, 1), (4, 2), (4, 4), (5, 1), (5, 5), (6, 1), (6, 2), (6, 3), (6, 6)]
[{(a,b) : a/b} for a in S for b in S]

how to print max size of list inside a list

For example:
alist=[[(0, 0), (0, 1), (1, 1), (1, 2), (2, 2), (2, 1), (2, 0), (1, 0), (3, 0)],
[(0, 2), (0, 3), (1, 3)],
[(0, 4), (1, 4), (2, 4), (0, 5), (0, 6), (1, 6), (2, 6), (3, 6)],
[(1, 5)],
[(2, 3), (3, 3), (3, 4), (3, 5), (2, 5), (3, 2), (3, 1)]]
for i in dlist:
print(len(i))
print(max(len(i))) #this gives me error
output:
5
9
3
8
1
7
I wanted to print out 9 as my output from the above list. How am I able to print the result?
Somewhat more terse
len(max(alist,key=len))
If you can be sure your nesting is only one level (that is, a list of lists):
print max(len(sublist) for sublist in alist)
functional style using map:
print max(map(len, alist))
If you want the actual index of the longest sublist:
max(((i,l) for i,l in enumerate(alist)), key=lambda t: len(t[1]))[0]
Or, as stated in comments:
max(enumerate(alist), key=lambda t: len(t[1]))[0]

Categories

Resources