I am trying to iterate over a Python 2D list. As the algorithm iterates over the list, it will add the key to a new list until a new value is detected. An operation is then applied to the list and then the list is emptied so that it can be used again as follows:
original_list = [('4', 'a'), ('3', 'a'), ('2', 'a'), ('1', 'b'), ('6', 'b')]
When the original_list is read by the algorithm it should evaluate the second value of each object and decipher if it is different from the previous value; if not, add it to a temporary list.
Here is the psedo code
temp_list = []
new_value = original_list[0][1] #find the first value
for key, value in original_list:
if value != new_value:
temp_list.append(new_value)
Should output
temp_list = ['4', '3', '2']
temp_list = []
prev_value = original_list[0][1]
for key, value in original_list:
if value == prev_value:
temp_list.append(key)
else:
do_something(temp_list)
print temp_list
temp_list = [key]
prev_value = value
do_something(temp_list)
print temp_list
# prints ['4', '3', '2']
# prints ['1', '6']
Not entirely sure what you are asking, but I think itertools.groupby could help:
>>> from itertools import groupby
>>> original_list = [('4', 'a'), ('3', 'a'), ('2', 'a'), ('1', 'b'), ('6', 'b')]
>>> [(zip(*group)[0], k) for k, group in groupby(original_list, key=lambda x: x[1])]
[(('4', '3', '2'), 'a'), (('1', '6'), 'b')]
What this does: It groups the items in the list by their value with key=lambda x: x[1] and gets tuples of keys corresponding to one value with (zip(*group)[0], k).
In case your "keys" do not repeat themselves, you could just use a defaultdict to "sort" the values based on keys, then extract what you need
from collections import defaultdict
ddict = defaultdict(list)
for v1, v2 in original_list:
ddict[v2].append(v1)
ddict values are now all temp_list:
>>> ddict["a"]
['4', '3', '2']
Related
I want to delete an element from a list of tuples and move the other items that had the same position.
Input:
a=[('201001', '-4'), ('201002', '2'), ('201003', '6')]
Desired output:
a=[('201001', '2'), ('201002', '6'), ('201003', 'na')]
I have tried the following code for it:
a[0](:- 1)
But I get SyntaxError: invalid syntax
I would appreciate it if you could suggest ways to solve this case.
Iterate through each element and set the tuple so that the second value is the value of the next element (except the last element because there is no element after it)
for i, val in enumerate(a):
try:
a[i] = (val[0], a[i+1][1])
except IndexError:
a[i] = (val[0], "na")
instead of error catching, you could also use the index:
arr_len = len(a) - 1
for i, val in enumerate(a):
if i == arr_len:
a[i] = (val[0], "na")
break
a[i] = (val[0], a[i+1][1])
Another way using zip:
a = [('201001', '-4'), ('201002', '2'), ('201003', '6')]
output = [(x, y) for (x, _), (_ ,y) in zip(a, [*a[1:], (None, 'na')])]
print(output) # [('201001', '2'), ('201002', '6'), ('201003', 'na')]
Here's a different way that lets you choose where you want to delete your number:
a = [('201001', '-4'), ('201002', '2'), ('201003', '6'), ('201004', '8'), ('201005', '3')]
def delete_item(position, arr): # position starting at 0, [(0,0), (1,1), (2,2), etc]
newNums = ([arr[x][1] for x in range(0, position)]
+ [arr[x][1] for x in range(position+1, len(arr))]
+ ['na'])
arr = [(arr[x][0], y) for x,y in zip(range(len(arr)), newNums)]
return arr
newTuple = delete_item(3, a)
Ouput:
[('201001', '-4'),
('201002', '2'),
('201003', '6'),
('201004', '3'),
('201005', 'na')]
Then you can keep putting the list of tuples in to remove a new number at a new position:
newTuple = delete_item(1, newTuple)
Output:
[('201001', '-4'),
('201002', '6'),
('201003', '3'),
('201004', 'na'),
('201005', 'na')]
Tuples are referenced the same way as a list which is a[0][-1] for the last element of the first tuple.
As tuples are immutable, you would be creating a new tuple every time you want to edit one.
One answer to your question would be to iterate through the values and update them like in the other answers.
A simpler way could be to first convert it into two lists, update and zip them back, like so:
from itertools import zip_longest
fst = list(map(lambda x: x[0], a))
snd = list(map(lambda x: x[1], a))
snd.pop(0)
a = list(zip_longest(fst, snd, fillvalue='na'))
I got a list like this:
[['a','b','1','2']['c','d','3','4']]
and I want to convert this list to dictionary something looks like this:
{
('a','b'):('1','2'),
('c','d'):('3','4')
}
for example, ('a', 'b') & ('c','d') for key
and ('1','2') &('3','4') for value
so I used code something like this
new_dict = {}
for i, k in enumerate(li[0:2]):
new_dict[k] =[x1[i] for x1 in li[2:]]
print(new_dict)
,but it caused unhashable type error 'list'
I tried several other way, but it didn't work well..
Is there any way that I can fix it?
You can't have list as key, but tuple is possible. Also you don't need to slice on your list, but on the sublist.
You need the 2 first values sublist[:2] as key and the corresponding values is the sublist from index 2 sublist[2:]
new_dict = {}
for sublist in li:
new_dict[tuple(sublist[:2])] = tuple(sublist[2:])
print(new_dict) # {('a', 'b'): ('1', '2'), ('c', 'd'): ('3', '4')}
The same with dict comprehension
new_dict = {tuple(sublist[:2]): tuple(sublist[2:]) for sublist in li}
print(new_dict) # {('a', 'b'): ('1', '2'), ('c', 'd'): ('3', '4')}
li = [['a','b','1','2'],['c','d','3','4']]
new_dict = {}
for item in li:
new_dict[(item[0], item[1])] = (item[2], item[3])
I would use list-comprehension following way:
lst = [['a','b','1','2']['c','d','3','4']]
dct = dict([(tuple(i[:2]),tuple(i[2:])) for i in lst])
print(dct)
or alternatively dict-comprehension:
dct = {tuple(i[:2]):tuple(i[2:]) for i in lst}
Output:
{('a', 'b'): ('1', '2'), ('c', 'd'): ('3', '4')}
Note that list slicing produce lists, which are mutable and can not be used as dict keys, so I use tuple to convert these to immutable tuples.
You can do it with dict comprehension:
li = [
['a', 'b', '1', '2'],
['c', 'd', '3', '4'],
]
new_dict = {(i[0], i[1]): (i[2], i[3]) for i in li}
print(new_dict)
# result
{('a', 'b'): ('1', '2'), ('c', 'd'): ('3', '4')}
Say, I have a two 2D list like below:
[[('a', '1'), ('a', '12'), ('a', '3')], [('b', '21'), ('b', '31')], [ ('c', '11')]]
The output I want to achieve is:
Output_list=[['1','12','3'], ['21','31'], ['11']]
The main complexity here is I want to achieve the output through a single list comprehension.
One of my attempts was:
print [a for innerList in fin_list1 for a,b in innerList]
Output:
['1', '12', '3', '21', '31', '11']
But, as you can see, though I have successfully retrieve the second elements of each tuple, i failed to retain my inner list structure.
We start with this:
>>> l = [[('a', '1'), ('a', '12'), ('a', '3')], [('b', '21'), ('b', '31')], [ ('c', '11')]]
Initially you tried to do something along these lines:
>>> [y for sublist in l for x, y in sublist]
['1', '12', '3', '21', '31', '11']
The mistake here is that this list comprehension is one-dimensional, i.e. all the values will be just integers instead of lists themselves
In order to make this two-dimensional, our values need to be lists. The easiest way to do this is by having our value expression be a nested list comprehension that iterates over the elements of the sublists of the original list:
>>> [[y for x, y in sublist] for sublist in l]
[['1', '12', '3'], ['21', '31'], ['11']]
Technically this is two list comprehensions, but obviously a list comprehension can be replaced by map as explained in Roberto's answer.
First, let's assign the data:
>>> data = [
[('a', '1'), ('a', '12'), ('a', '3')],
[('b', '21'), ('b', '31')],
[('c', '11')],
]
You can use itemgetter to create a function that gets one element from the tuple:
>>> from operator import itemgetter
>>> first = itemgetter(0)
>>> second = itemgetter(1)
Now you can transform inner lists by using map:
>>> [map(first, row) for row in data]
[['a', 'a', 'a'], ['b', 'b'], ['c']]
>>> [map(second, row) for row in data]
[['1', '12', '3'], ['21', '31'], ['11']]
You could also create first and second without using itemgetter:
def first(xs):
return xs[0]
def second(xs):
return xs[1]
the_list = [[('a', '1'), ('a', '12'), ('a', '3')], [('b', '21'), ('b', '31')], [ ('c', '11')]]
new_list = [[x[1] for x in y] for y in the_list]
print new_list
Output:
[['1', '12', '3'], ['21', '31'], ['11']]
I've created a dictionary from a tuple, but can't seem to find an answer as to how I'd switch my keys and values without editing the original tuple. This is what I have so far:
tuples = [('a', '1'), ('b', '1'), ('c', '2'), ('d', '3')]
dic = dict(tuples)
print dic
This gives the output:
{'a': '1', 'b': ''1', 'c': '2', 'd': '3'}
But I'm looking for:
{'1': 'a' 'b', '2': 'c', '3': 'd'}
Is there a simple code that could produce this?
Build a dictionary in a loop, collecting your values into lists:
result = {}
for value, key in tuples:
result.setdefault(key, []).append(value)
The dict.setdefault() method will set and return a default value if the key isn't present. Here I used it to set a default empty list value if the key is not present, so the .append(value) is applied to a list object, always.
Don't try to make this a mix of single string and multi-string list values, you'll only complicate matters down the road.
Demo:
>>> tuples = [('a', '1'), ('b', '1'), ('c', '2'), ('d', '3')]
>>> result = {}
>>> for value, key in tuples:
... result.setdefault(key, []).append(value)
...
>>> result
{'1': ['a', 'b'], '3': ['d'], '2': ['c']}
from operator import itemgetter
from itertools import groupby
first = itemgetter(0)
second = itemgetter(1)
d = dict((x, [v for _, v in y]) for x, y in groupby(sorted(tuples, key=second), key=second)
groupby groups the tuples into a new iterator of tuples, whose first element is the unique second item of each of the original, and whose second element is another iterator consisting of the corresponding first items. A quick example (pretty-printed for clarity):
>>> list(groupby(sorted(tuples, key=second), key=second)))
[('1', <itertools._grouper object at 0x10910b8d0>),
('2', <itertools._grouper object at 0x10910b790>),
('3', <itertools._grouper object at 0x10910b750>)]
The sorting by the same key used by groupby is necessary to ensure all like items are grouped together; groupby only makes one pass through the list.
The subiterators consist of tuples like ('1', 'a'), so the second value in each item is the one we want to add to the value in our new dictionary.
I have a defaultdict that contains the calculation of the average position of number ( Euler problem )
[('1', 0.6923076923076923), ('0', 2.0), ('3', 0.2222222222222222),
('2', 1.0909090909090908), ('7', 0.0), ('6', 0.875),
('9', 1.6923076923076923),('8', 1.3333333333333333)]
I'm trying to get this information into simple string instead of doing it manually from 0 - 2.
The end result I'm looking for is something like
73162890
I don't know any good way to extracting them without using many if-else and for-loops.
Is there any simple and good way of doing this in python?
If your dict is d, then items = d.items() gives you a list of pairs, like you have. Once you have this list, you can sort it by the second element:
ordered = sorted(items, key=lambda (_, value): value) # Not Python 3
# or,
ordered = sorted(items, key=lambda x: x[1])
# or,
import operator
ordered = sorted(items, key=operator.itemgetter(1))
Once we have the list in sorted order, we just need to extract the strings from each one, and glue them all together:
result = ''.join(string for (string, _) in ordered)
(Note that I'm calling unused parameters _, there's nothing special about the _ in a Python program.)
In [36]: ''.join([key for key, val in sorted(data, key = lambda item: item[1])])
Out[36]: '73162890'
Explanation:
This sorts the data according to the second value for each item in data.
In [37]: sorted(data, key = lambda item: item[1])
Out[37]:
[('7', 0.0),
('3', 0.2222222222222222),
('1', 0.6923076923076923),
('6', 0.875),
('2', 1.0909090909090908),
('8', 1.3333333333333333),
('9', 1.6923076923076923),
('0', 2.0)]
Now we can collect the first value in each item using a list comprehension:
In [38]: [key for key, val in sorted(data, key = lambda item: item[1])]
Out[38]: ['7', '3', '1', '6', '2', '8', '9', '0']
And join these items into a string using ''.join:
In [39]: ''.join([key for key, val in sorted(data, key = lambda item: item[1])])
Out[39]: '73162890'