Related
I have a list of lists, let's call it foo
foo = [['A', '1'], ['C', '5', 'D', '9', 'E'], ['F'], ['G', 'H']]
and another list bar
bar = ['A', 'C', 'D', 'F', 'H']
I wanted search the elements of bar in foo and if they are find then the next element is to be picked and create a dictionary with keys as elements of bar.
What I tried:
pay = {}
for i in bar:
for j in foo:
for k in j:
if i == k:
try:
pay[i] = k+1
except:
pay[i] = '-'
Expected Output:
pay = {'A':1,
'C':5,
'D':9,
'F':'-',
'H':'-'}
You've missed,
Accessing the proper index to find the next element.
Using == operator instead of in property to check the value's presence in the list.
Solution:
bar = ['A', 'C', 'D', 'F', 'H']
foo = [['A', '1'], ['C', '5', 'D', '9', 'E'], ['F'], ['G', 'H']]
output_dict = {}
for element in foo:
for foo_element in element:
if foo_element in bar:
try:
output_dict[foo_element] = element[element.index(foo_element) + 1]
except:
output_dict[foo_element] = '-'
print(output_dict)
Output:
{'D': '9', 'H': '-', 'F': '-', 'C': '5', 'A': '1'}
I would normalize the data, i.e. flatten the foo and convert it to a dict of all pairs {item: next_item}.
Then just get the data from this dict.
foo = [['A', '1'], ['C', '5', 'D', '9', 'E'], ['F'], ['G', 'H']]
bar = ['A', 'C', 'D', 'F', 'H']
pdict = {k:v for s in foo for k, v in zip(s, s[1:])}
# print(pdict) # uncomment to check
pay = {k: pdict.get(k, '-') for k in bar}
print(pay) # {'A': '1', 'C': '5', 'D': '9', 'F': '-', 'H': '-'}
As #kuro mentioned, you can use enumerate function or else you can simply iterate over the the indices as below.
foo = [['A', '1'], ['C', '5', 'D', '9', 'E'], ['F'], ['G', 'H']]
bar = ['A', 'C', 'D', 'F', 'H']
pay = {}
for i in bar:
for j in foo:
for k in range(len(j)):
if i == j[k]:
try:
pay[i] = j[k + 1]
except IndexError:
pay[i] = '-'
print(pay)
Output:
{'A': '1', 'C': '5', 'D': '9', 'F': '-', 'H': '-'}
list_of_lists = foo
flattened = [val for sublist in list_of_lists for val in sublist] + ['-']
pay = {}
for bar_val in bar:
pos = flattened.index(bar_val)
try:
pay[bar_val] = int(flattened[pos+1])
except ValueError as e:
pay[bar_val] = '-'
print(pay)
Output:
{'A': 1, 'C': 5, 'D': 9, 'F': '-', 'H': '-'}
You can try to do it this way as well:
foo = [['A', '1'], ['C', '5', 'D', '9', 'E'], ['F'], ['G', 'H']]
bar = ['A', 'C', 'D', 'F', 'H']
pay = dict()
# loop through bar
for i in range(len(bar)):
# loop through foo
for j in range(len(foo)):
# loop through elements of foo
for k in range(len(foo[j])):
# check if data in foo matches element in bar
if bar[i] == foo[j][k]:
# check if data in foo is the last element in the sub-list
if (len(foo[j]) > k+1):
pay[bar[i]] = foo[j][k+1]
else:
pay[bar[i]] = '-'
else:
pass
# iterate through dict and print its contents
for k, v in pay.items():
print(k, v)
def get_next(elt, sublist):
try:
return sublist[sublist.index(elt) + 1]
except:
return '-'
final_dict = { elt: get_next(elt, sub) for sub in foo for elt in sub if elt in bar}
print(final_dict) # {'A': '1', 'C': '5', 'D': '9', 'F': '-', 'H': '-'}
Just another solution using generators:
foo = [['A', '1'], ['C', '5', 'D', '9', 'E'], ['F'], ['G', 'H']]
from itertools import chain
def get_pairs(it):
stack = None
while True:
try:
x = stack if stack else next(it)
try:
y = next(it)
if y.isdigit():
yield x, y
stack = None
else:
yield x, "-"
stack = y
except StopIteration:
yield x, "-"
break
except StopIteration:
break
result = dict([item for item in get_pairs(chain.from_iterable(foo))])
print(result)
Which yields
{'A': '1', 'C': '5', 'D': '9', 'E': '-', 'F': '-', 'G': '-', 'H': '-'}
I have my data in txt file.
1 B F 2019-03-10
1 C G 2019-03-11
1 B H 2019-03-10
1 C I 2019-03-10
1 B J 2019-03-10
2 A K 2019-03-10
1 D L 2019-03-10
2 D M 2019-03-10
2 E N 2019-03-11
1 E O 2019-03-10
What I need to do is to split the data according to the first column.
So all rows with number 1 in the first column go to one list( or dictionary or whatever) and all rows with number 2 in the first column do to other list or whatever. This is a sample data, in original data we do not know how many different numbers are in the first column.
What I have to do next is to sort the data for each key (in my case for numbers 1 and 2) by date and time. I could do that with the data.txt, but not with the dictionary.
with open("data.txt") as file:
reader = csv.reader(file, delimiter="\t")
data=sorted(reader, key=itemgetter(0))
lines = sorted(data, key=itemgetter(3))
lines
OUTPUT:
[['1', 'B', 'F', '2019-03-10'],
['2', 'D', 'M', '2019-03-10'],
['1', 'B', 'H', '2019-03-10'],
['1', 'C', 'I', '2019-03-10'],
['1', 'B', 'J', '2019-03-10'],
['1', 'D', 'L', '2019-03-10'],
['2', 'A', 'K', '2019-03-10'],
['1', 'E', 'O', '2019-03-10'],
['1', 'C', 'G', '2019-03-11'],
['2', 'E', 'N', '2019-03-11']]
So what I need is to group the data by the number in the first column as well as to sort this by the date and time. Could anyone please help me to combine these two codes somehow? I am not sure if I had to use a dictionary, maybe there is another way to do that.
You can sort corresponding list for each key after splitting the data according to the first column
def sort_by_time(key_items):
return sorted(key_items, key=itemgetter(3))
d = {k: sort_by_time(v) for k, v in d.items()}
If d has separate elements for time and for date, then you can sort by several columns:
sorted(key_items, key=itemgetter(2, 3))
itertools.groupby can help build the lists:
from operator import itemgetter
from itertools import groupby
from pprint import pprint
# Read all the data splitting on whitespace
with open('data.txt') as f:
data = [line.split() for line in f]
# Sort by indicated columns
data.sort(key=itemgetter(0,3,4))
# Build a dictionary keyed on the first column
# Note: data must be pre-sorted by the groupby key for groupby to work correctly.
d = {group:list(items) for group,items in groupby(data,key=itemgetter(0))}
pprint(d)
Output:
{'1': [['1', 'B', 'F', '2019-03-10', '16:13:38.935'],
['1', 'B', 'H', '2019-03-10', '16:13:59.045'],
['1', 'C', 'I', '2019-03-10', '16:14:07.561'],
['1', 'B', 'J', '2019-03-10', '16:14:35.371'],
['1', 'D', 'L', '2019-03-10', '16:14:40.854'],
['1', 'E', 'O', '2019-03-10', '16:15:05.878'],
['1', 'C', 'G', '2019-03-11', '16:14:39.999']],
'2': [['2', 'D', 'M', '2019-03-10', '16:13:58.641'],
['2', 'A', 'K', '2019-03-10', '16:14:43.224'],
['2', 'E', 'N', '2019-03-11', '16:15:01.807']]}
I have lists like:
['a', '2', 'b', '1', 'c', '4']
['d', '5', 'e', '7', 'f', '4', 'g', '6']
And I want to make a dictionary consist of keys as letters and values as numbers. I mean:
{'a': 2, 'b': 1, 'c': 4, 'd':5, 'e':7, 'f':4, 'g':6}
You can try:
>>> l = ['a', '2', 'b', '1', 'c', '4']
>>> it = iter(l)
>>> dict(zip(it, it))
{'a': '2', 'c': '4', 'b': '1'}
First you create an iterator out of the list. Then with zip of the iterator with itself you take pair of values from the list. Finally, with dict you transform these tuples to your wanted dictionary.
If you also want to do the string to number conversion, then use:
{x: int(y) for x, y in zip(it, it)}
EDIT
If you don't want to use zip then:
{x: int(next(it)) for x in it}
l = ['a', '2', 'b', '1', 'c', '4']
d = {k:v for k,v in zip(l[::2], l[1::2])}
Or if you want the numbers to be actual numbers:
l = ['a', '2', 'b', '1', 'c', '4']
d = {k:int(v) for k,v in zip(l[::2], l[1::2])}
Use float(v) instead of int(v) if the numbers have the potential to be floating-point values instead of whole numbers.
Without using any built-in functions:
l = ['a', '2', 'b', '1', 'c', '4']
d = {}
l1 = l[::2]
l2 = l[1::2]
idx = 0
while 1:
try:
d[l1[idx]] = l2[idx]
idx += 1
except IndexError:
break
You can split the lists into two, one containing the letters and the other containing the keys, with
key_list = old_list[::2]
value_list = old_list[1::2]
Then you can loop over the two lists at once with zip and you can make the dictionary.
The challenge is that I want to count the number of times a certain pattern of items occurs in a sub-list at certain indices.
For example, I'd like to count the number of times a unique patter occurs at index 0 and index 1. 'a' and 'z' occur three times below at index 0 and index 1 while '1' and '2' occur two times below at index 0 and index 1. I'm only concerned at the pair that occurs at index 0 and 1 and I'd like to know the count of unique pairs that are there and then append that count back to the sub-list.
List = [['a','z','g','g','g'],['a','z','d','d','d'],['a','z','z','z','d'],['1','2','f','f','f'],['1','2','3','f','f'],['1','1','g','g','g']]
Desired_List = [['a','z','g','g','g',3],['a','z','d','d','d',3],['a','z','z','z','d',3],['1','2','f','f','f',2],['1','2','3','f','f',2],['1','1','g','g','g',1]]
Currently, my attempt is this:
from collections import Counter
l1 = Counter(map(lambda x: (x[0] + "|" + x[1]),List)
Deduped_Original_List = map(lambda x: Counter.keys().split("|"),l1)
Counts = map(lambda x: Counter.values(),l1)
for ele_a, ele_b in zip(Deduped_Original_List, Counts):
ele_a.append(ele_b)
This clearly doesn't work because in the process I lose index 2,3, and 4.
You can use list comprehension with collections.Counter:
from collections import Counter
lst = [['a','z','g','g','g'],['a','z','d','d','d'],['a','z','z','z','d'],['1','2','f','f','f'],['1','2','3','f','f'],['1','1','g','g','g']]
cnt = Counter([tuple(l[:2]) for l in lst])
lst_output = [l + [cnt[tuple(l[:2])]] for l in lst]
print lst_output
Ouput:
[['a', 'z', 'g', 'g', 'g', 3], ['a', 'z', 'd', 'd', 'd', 3], ['a', 'z', 'z', 'z', 'd', 3], ['1', '2', 'f', 'f', 'f', 2], ['1', '2', '3', 'f', 'f', 2], ['1', '1', 'g', 'g', 'g', 1]]
>>> import collections
>>> List = [['a','z','g','g','g'],['a','z','d','d','d'],['a','z','z','z','d'],['1','2','f','f','f'],['1','2','3','f','f'],['1','1','g','g','g']]
>>> patterns = ['az', '12']
>>> answer = collections.defaultdict(int)
>>> for subl in List:
... for pattern in patterns:
... if all(a==b for a,b in zip(subl, pattern)):
... answer[pattern] += 1
... break
...
>>> for i,subl in enumerate(List):
... if ''.join(subl[:2]) in answer:
... List[i].append(answer[''.join(subl[:2])])
...
>>> List
[['a', 'z', 'g', 'g', 'g', 3], ['a', 'z', 'd', 'd', 'd', 3], ['a', 'z', 'z', 'z', 'd', 3], ['1', '2', 'f', 'f', 'f', 2], ['1', '2', '3', 'f', 'f', 2], ['1', '1', 'g', 'g', 'g']]
>>>
I like the Counter approach of YS-L. Here is another approach:
>>> List = [['a','z','g','g','g'], ['a','z','d','d','d'], ['a','z','z','z','d'],['1','2','f','f','f'], ['1','2','3','f','f'], ['1','1','g','g','g']]
>>> d = {}
>>> for i in List:
key = i[0] + i[1]
if not d.get(key, None): d[key] = 1
else: d[key] += 1
>>> Desired_List = [li + [d[li[0] + li[1]]] for li in List]
>>> Desired_List
[['a', 'z', 'g', 'g', 'g', 3], ['a', 'z', 'd', 'd', 'd', 3], ['a', 'z', 'z', 'z', 'd', 3], ['1', '2', 'f', 'f', 'f', 2], ['1', '2', '3', 'f', 'f', 2], ['1', '1', 'g', 'g', 'g', 1]]
I have a complex matrix that looks like this:
[[ ['x', '1', '2', '3', '4'],
['y', '5', '6', '7', '8']],
[ ['x', 'a', 'b', 'c', 'd'],
['y', 'e', 'f', 'g', 'h'] ] ]
I want to turn it into this:
['x', '1a', '2b', '3c', '4d'],
['y', '5e', '6f', '7g', '8h']
I'm busting my head but not managing to achieve the result. Also, even though I only have two groups of nested 5-items long lists, in theory I want to solve this for an infinite number of groups of the same size.
You can use a dict here:
>>> from operator import add
>>> lis = [[ ['x', '1', '2', '3', '4'],
['y', '5', '6', '7', '8']],
[ ['x', 'a', 'b', 'c', 'd'],
['y', 'e', 'f', 'g', 'h'] ] ]
>>> dic = {}
for item in lis:
for x in item:
k, v = x[0], x[1:]
if k in dic:
dic[k] = map(add, dic[k], v)
else:
dic[k] = v
...
>>> dic
{'y': ['5e', '6f', '7g', '8h'], 'x': ['1a', '2b', '3c', '4d']}
#list of lists
>>> [[k] + v for k, v in dic.iteritems()]
[['y', '5e', '6f', '7g', '8h'], ['x', '1a', '2b', '3c', '4d']]
Another solution using zip, reduce and a list comprehension:
>>> from operator import add
>>> def func(x, y):
... return map(add, x, y[1:])
>>> [[item[0][0]] + reduce(func, item[1:], item[0][1:]) for item in zip(*lis)]
[['x', '1a', '2b', '3c', '4d'], ['y', '5e', '6f', '7g', '8h']]
Here's a "fun" solution. Since you did not provide any information about your array's structure, I assumed the easiest variant:
import numpy
a = numpy.array([[
['x', '1', '2', '3', '4'],
['y', '5', '6', '7', '8']],
[
['x', 'a', 'b', 'c', 'd'],
['y', 'e', 'f', 'g', 'h']]],
dtype=numpy.object)
res = a[0].copy()
for chunk in a[1:]:
res[:,1:] += chunk[:,1:]
print(res)