Related
I try to get execute a program to get a sorted list in increasing order of last element in each tuple in a given list using decorators.
Here is my decorator:->
import functools
List2 =[]
List3 =[]
def parapassing_decorator(tuple1):
def getSortedElement(func):
#functools.wraps(func)
def inner1(*args, **kwargs):
list2 = func(*args, **kwargs)
output = [ q for q in tuple1 for l in list2 if l == int(q[1],)]
print(output)
return inner1;
Now get the all last element from all tuples and sort it here
#parapassing_decorator(tuple1 = ([(2, 5), (1, 2), (4, 4), (2, 3), (2, 1)]))
def getlastelements(tuple1):
for t in tuple1:
List2.append(t)
List2.sort()
return List2
now decorator is passing with getlastelements function to compare with all tuples last elements and rearrange it in a list.
calling method:-
getlastelements(tuple1=[(2, 5), (1, 2), (4, 4), (2, 3), (2, 1)])
But I got the error like:-
35 #parapassing_decorator(tuple1 = ([(2, 5), (1, 2), (4, 4), (2, 3), (2, 1)]))
---> 36 def getlastelements(tuple1):
37 for t in tuple1:
38 List2.append(t)
TypeError: 'NoneType' object is not callable
Sorry for trouble you all.
I think this solution is usable.
import functools
List2 =[]
List3 =[]
def parapassing_decorator(tuple1):
#functools.wraps(tuple1)
def inner1(func):
list2 = func(tuple1)
output = [ q for l in list2 for q in tuple1 if l == int(q[1],)]
List3.append(output)
print(output)
return inner1;
#parapassing_decorator(tuple1 = ([(2, 5), (1, 2), (4, 4), (2, 3), (2, 1)]))
def getlastelements(x):
for t in x:
List2.append(t[1])
List2.sort()
return List2
I've got
desc = ['(4,1);(1,4)', '(2,3);(3,2)', '(4,2);(2,4);(1,3);(3,1)', '(1,2);(2,1);(4,3);(3,4)']
and I want the output to be
[[(4, 1), (1, 4)], [(2, 3), (3, 2)], [(4, 2), (2, 4), (1, 3), (3, 1)], [(1, 2), (2, 1), (4, 3), (3, 4)]]
So far I've tried:
for x in range(len(desc)):
desc[x] = desc[x].split(';')
for y in range(len(desc[x])):
desc[x][y] = eval(desc[x][y])
but there is a syntax error saying 'unexpected EOF while parsing. How do I fix my code?
For the last two lines of my code I was just trying to extract the tuples from the strings containing them, is there anything else I could use except for eval()?
Unexpected EOF is caused by the indentation of the second for loop.
for x in range(len(desc)):
desc[x] = desc[x].split(';')
for y in range(len(desc[x])): # this has one tab to much
desc[x][y] = eval(desc[x][y])
This is how it should look like:
for x in range(len(desc)):
desc[x] = desc[x].split(';')
for y in range(len(desc[x])):
desc[x][y] = eval(desc[x][y])
You want to split each item of your list with the separator ';'. You need to parse your list :
for element in desc and split each element according to this separator :
temp = element.split(';'). You can then add to your output list the list [temp[0], temp[1]]
desc = ['(4,1);(1,4)', '(2,3);(3,2)', '(4,2);(2,4);(1,3);(3,1)', '(1,2);(2,1);(4,3);(3,4)']
output = []
for element in desc:
temps = element.split(";")
output.append([temps[0], temps[1]])
print(output)
# [['(4,1)', '(1,4)'], ['(2,3)', '(3,2)'], ['(4,2)', '(2,4)'], ['(1,2)', '(2,1)']]
To remove the '' you have to transform your items into actual tuples with the integers inside :
desc = ['(4,1);(1,4)', '(2,3);(3,2)', '(4,2);(2,4);(1,3);(3,1)', '(1,2);(2,1);(4,3);(3,4)']
output = []
for element in desc:
temps = element.split(";")
tuples_to_add = []
for i in temps:
tuples_to_add.append(tuple([int(i.strip('()')[0]), int(i.strip('()')[-1])]))
output.append(tuples_to_add)
print(output)
[[(4, 1), (1, 4)], [(2, 3), (3, 2)], [(4, 2), (2, 4), (1, 3), (3, 1)], [(1, 2), (2, 1), (4, 3), (3, 4)]]
I have seen some similar answers, but I can't find something specific for this case.
I have a list of tuples:
[(5, 0), (3, 1), (3, 2), (5, 3), (6, 4)]
What I want is to remove tuples from this list only when first element of tuple has occurred previously in the list and the tuple which remains should have the smallest second element.
So the output should look like this:
[(5, 0), (3, 1), (6, 4)]
Here's a linear time approach that requires two iterations over your original list.
t = [(5, 0), (3, 1), (3, 2), (5, 3), (6, 4)] # test case 1
#t = [(5, 3), (3, 1), (3, 2), (5, 0), (6, 4)] # test case 2
smallest = {}
inf = float('inf')
for first, second in t:
if smallest.get(first, inf) > second:
smallest[first] = second
result = []
seen = set()
for first, second in t:
if first not in seen and second == smallest[first]:
seen.add(first)
result.append((first, second))
print(result) # [(5, 0), (3, 1), (6, 4)] for test case 1
# [(3, 1), (5, 0), (6, 4)] for test case 2
Here is a compact version I came up with using OrderedDict and skipping replacement if new value is larger than old.
from collections import OrderedDict
a = [(5, 3), (3, 1), (3, 2), (5, 0), (6, 4)]
d = OrderedDict()
for item in a:
# Get old value in dictionary if exist
old = d.get(item[0])
# Skip if new item is larger than old
if old:
if item[1] > old[1]:
continue
#else:
# del d[item[0]]
# Assign
d[item[0]] = item
list(d.values())
Returns:
[(5, 0), (3, 1), (6, 4)]
Or if you use the else-statement (commented out):
[(3, 1), (5, 0), (6, 4)]
Seems to me that you need to know two things:
The tuple that has the smallest second element for each first element.
The order to index each first element in the new list
We can get #1 by using itertools.groupby and a min function.
import itertools
import operator
lst = [(3, 1), (5, 3), (5, 0), (3, 2), (6, 4)]
# I changed this slightly to make it harder to accidentally succeed.
# correct final order should be [(3, 1), (5, 0), (6, 4)]
tmplst = sorted(lst, key=operator.itemgetter(0))
groups = itertools.groupby(tmplst, operator.itemgetter(0))
# group by first element, in this case this looks like:
# [(3, [(3, 1), (3, 2)]), (5, [(5, 3), (5, 0)]), (6, [(6, 4)])]
# note that groupby only works on sorted lists, so we need to sort this first
min_tuples = {min(v, key=operator.itemgetter(1)) for _, v in groups}
# give the best possible result for each first tuple. In this case:
# {(3, 1), (5, 0), (6, 4)}
# (note that this is a set comprehension for faster lookups later.
Now that we know what our result set looks like, we can re-tackle lst to get them in the right order.
seen = set()
result = []
for el in lst:
if el not in min_tuples: # don't add to result
continue
elif el not in seen: # add to result and mark as seen
result.append(el)
seen.add(el)
This will do what you need:
# I switched (5, 3) and (5, 0) to demonstrate sorting capabilities.
list_a = [(5, 3), (3, 1), (3, 2), (5, 0), (6, 4)]
# Create a list to contain the results
list_b = []
# Create a list to check for duplicates
l = []
# Sort list_a by the second element of each tuple to ensure the smallest numbers
list_a.sort(key=lambda i: i[1])
# Iterate through every tuple in list_a
for i in list_a:
# Check if the 0th element of the tuple is in the duplicates list; if not:
if i[0] not in l:
# Add the tuple the loop is currently on to the results; and
list_b.append(i)
# Add the 0th element of the tuple to the duplicates list
l.append(i[0])
>>> print(list_b)
[(5, 0), (3, 1), (6, 4)]
Hope this helped!
Using enumerate() and list comprehension:
def remove_if_first_index(l):
return [item for index, item in enumerate(l) if item[0] not in [value[0] for value in l[0:index]]]
Using enumerate() and a for loop:
def remove_if_first_index(l):
# The list to store the return value
ret = []
# Get the each index and item from the list passed
for index, item in enumerate(l):
# Get the first number in each tuple up to the index we're currently at
previous_values = [value[0] for value in l[0:index]]
# If the item's first number is not in the list of previously encountered first numbers
if item[0] not in previous_values:
# Append it to the return list
ret.append(item)
return ret
Testing
some_list = [(5, 0), (3, 1), (3, 2), (5, 3), (6, 4)]
print(remove_if_first_index(some_list))
# [(5, 0), (3, 1), (6, 4)]
I had this idea without seeing the #Anton vBR's answer.
import collections
inp = [(5, 0), (3, 1), (3, 2), (5, 3), (6, 4)]
od = collections.OrderedDict()
for i1, i2 in inp:
if i2 <= od.get(i1, i2):
od.pop(i1, None)
od[i1] = i2
outp = list(od.items())
print(outp)
How will I do the following?
class a:
def get(self):
return (1, 2)
i = a() #this is variable that i wont have access directly and should be accessed only from list P below
P = [i, i, i, i]
Q = [P, P, P, P]
I want is
L = [list of all i.get() results iterating through Q and P]
for eg
L = [px.get() for px in P for P in Q] # I want something like this
i.e
L = [(1, 2), (1, 2), (1, 2), (1, 2), (1, 2), (1, 2), (1, 2), (1, 2), (1, 2), (1, 2), (1, 2), (1, 2), (1, 2), (1, 2), (1, 2), (1, 2)]
Use a list comprehension:
L = [i.get() for P in Q for i in P]
This gives you [Q[0][0].get(), Q[0][1].get(), ..., Q[-1][-2].get(), Q[-1][-1].get()]
The double loop is just like a nested for loop outside of a list comprehension, the above is the equivalent of:
L = []
for P in Q:
for i in P:
L.append(i.get())
The list comprehension follows the same order of loops, nesting is translated to loops being listed from left to right.
Replicating a list can be done with the * operator in Python (i.e. multiplying a list):
>>> [i.get()] * (len(P) + len(Q))
[(1,2), (1,2), (1,2), (1,2), (1,2), (1,2), (1,2), (1,2)]
I have a list of tuples that looks like this:
lst = [(0, 0), (2, 3), (4, 3), (5, 1)]
What is the best way to accumulate the sum of the first and secound tuple elements? Using the example above, I'm looking for the best way to produce this list:
new_lst = [(0, 0), (2, 3), (6, 6), (11, 7)]
I am looking for a solution in Python 2.6
I would argue the best solution is itertools.accumulate() to accumulate the values, and using zip() to split up your columns and merge them back. This means the generator just handles a single column, and makes the method entirely scalable.
>>> from itertools import accumulate
>>> lst = [(0, 0), (2, 3), (4, 3), (5, 1)]
>>> list(zip(*map(accumulate, zip(*lst))))
[(0, 0), (2, 3), (6, 6), (11, 7)]
We use zip() to take the columns, then apply itertools.accumulate() to each column, then use zip() to merge them back into the original format.
This method will work for any iterable, not just sequences, and should be relatively efficient.
Prior to 3.2, accumulate can be defined as:
def accumulate(iterator):
total = 0
for item in iterator:
total += item
yield total
(The docs page gives a more generic implementation, but for this use case, we can use this simple implementation).
How about this generator:
def accumulate_tuples(iterable):
accum_a = accum_b = 0
for a, b in iterable:
accum_a += a
accum_b += b
yield accum_a, accum_b
If you need a list, just call list(accumulate_tuples(your_list)).
Here's a version that works for arbitrary length tuples:
def accumulate_tuples(iterable):
it = iter(iterable):
accum = next(it) # initialize with the first value
yield accum
for val in it: # iterate over the rest of the values
accum = tuple(a+b for a, b in zip(accum, val))
yield accum
>> reduce(lambda x,y: (x[0] + y[0], x[1] + y[1]), lst)
(11, 7)
EDIT. I can see your updated question. To get the running list you can do:
>> [reduce(lambda x,y: (x[0]+y[0], x[1]+y[1]), lst[:i]) for i in range(1,len(lst)+1)]
[(0, 0), (2, 3), (6, 6), (11, 7)]
Not super efficient, but at least it works and does what you want :)
This works for any length of tuples or other iterables.
from collections import defaultdict
def accumulate(lst):
sums = defaultdict(int)
for item in lst:
for index, subitem in enumerate(item):
sums[index] += subitem
yield [sums[index] for index in xrange(len(sums))]
print [tuple(x) for x in accumulate([(0, 0), (2, 3), (4, 3), (5, 1)])]
In Python 2.7+ you would use a Counter instead of defaultdict(int).
This is a really poor way (in terms of performance) to do this because list.append is expensive, but it works.
last = lst[0]
new_list = [last]
for t in lst[1:]:
last += t
new_list.append(last)
Simple method:
>> x = [(0, 0), (2, 3), (4, 3), (5, 1)]
>>> [(sum(a for a,b in x[:t] ),sum(b for a,b in x[:t])) for t in range(1,len(x)+1)]
[(0, 0), (2, 3), (6, 6), (11, 7)]
lst = [(0, 0), (2, 3), (4, 3), (5, 1)]
lst2 = [lst[0]]
for idx in range(1, len(lst)):
newItem = [0,0]
for idx2 in range(0, idx + 1):
newItem[0] = newItem[0] + lst[idx2][0]
newItem[1] = newItem[1] + lst[idx2][1]
lst2.append(newItem)
print(lst2)
You can use the following function
>>> def my_accumulate(lst):
new_lst = [lst[0]]
for x, y in lst[1:]:
new_lst.append((new_lst[-1][0]+x, new_lst[-1][1]+y))
return new_lst
>>> lst = [(0, 0), (2, 3), (4, 3), (5, 1)]
>>> my_accumulate(lst)
[(0, 0), (2, 3), (6, 6), (11, 7)]
Changed my code to a terser version:
lst = [(0, 0), (2, 3), (4, 3), (5, 1)]
def accumulate(the_list):
the_item = iter(the_list)
accumulator = next(the_item)
while True:
yield accumulator
accumulator = tuple(x+y for (x,y) in zip (accumulator, next(the_item)))
new_lst = list(accumulate(lst))