I am using Python to read data from a file and assign the strings in one column to the integers in another column. This is what I have so far:
flight_source_graph = {}
with open('flightinfo.csv') as csvfile:
reader = csv.reader(csvfile, delimiter=',')
next(reader, None)
for row in reader:
flight_source = row[0] #'ABC','XYZ','TWR'
flight_dep_time = row[2] #'0','10','7'
#departure information
if flight_source in flight_source_graph:
flight_source_graph[flight_source].append(flight_dep_time)
else:
flight_source_graph[flight_source] = [flight_dep_time]
Output:
{'ABC': ['0', '10', '7'], 'XYZ': ['4','7','10'], 'TWR': ['9','11','15','24']}
Now that I have this data showing what's assigned to what, how would I go about transforming it to create a list that looks like this:
[('ABC', '0'),('ABC','10'),('ABC','7')]
#Where each of the values in the parentheses () would signify a node
This is one way to combine the keys with the list values:
if __name__ == '__main__':
flight_info = {'ABC': ['0', '10', '7'], 'XYZ': ['4', '7', '10'], 'TWR': ['9', '11', '15', '24']}
flight_graph = []
for k, v in flight_info.items():
for i in v:
flight_graph.append((k, i))
print(flight_graph)
# [('ABC', '0'), ('ABC', '10'), ('ABC', '7'), ('XYZ', '4'), ('XYZ', '7'), ('XYZ', '10'), ('TWR', '9'), ('TWR', '11'), ('TWR', '15'), ('TWR', '24')]
Related
My question is if there's any way to attribute the numbers in the first column to the ones in the second column. So that I can read the numbers in the second column but have them connected to the ones in the first column in some way, so that I can sort them as I do in the sorted_resistances list but after sorting them I replace them with the values in the first column that we're assigned to each of the values.
For information in the code it's opening up from a file the list that's why it's programed like that
1 30000
2 30511
3 30052
4 30033
5 30077
6 30055
7 30086
8 30044
9 30088
10 30019
11 30310
12 30121
13 30132
with open("file.txt") as file_in:
list_of_resistances = []
for line in file_in:
list_of_resistances.append(int(line.split()[1]))
sorted_resistances = sorted(list_of_resistances)
If you want to keep the correlation between the values in the two columns, you can keep all of the values from each line in a tuple (or list), and then sort the list of tuples using a specific piece by passing a lambda function to the key parameter of the sorted() function that tells it to use the second piece of each tuple as the sort value.
In this example, I used pprint.pprint to make the output the of the lists easier to read.
from pprint import pprint
with open("file.txt") as file_in:
list_of_resistances = []
for line in file_in:
list_of_resistances.append(tuple(line.strip().split(' ')))
print("Unsorted values:")
pprint(list_of_resistances)
sorted_resistances = sorted(list_of_resistances, key=lambda x: x[1])
print("\nSorted values:")
pprint(sorted_resistances)
print("\nSorted keys from column 1:")
pprint([x[0] for x in sorted_resistances])
Output:
Unsorted values:
[('1', '30000'),
('2', '30511'),
('3', '30052'),
('4', '30033'),
('5', '30077'),
('6', '30055'),
('7', '30086'),
('8', '30044'),
('9', '30088'),
('10', '30019'),
('11', '30310'),
('12', '30121'),
('13', '30132')]
Sorted values:
[('1', '30000'),
('10', '30019'),
('4', '30033'),
('8', '30044'),
('3', '30052'),
('6', '30055'),
('5', '30077'),
('7', '30086'),
('9', '30088'),
('12', '30121'),
('13', '30132'),
('11', '30310'),
('2', '30511')]
Sorted keys from column 1:
['1', '10', '4', '8', '3', '6', '5', '7', '9', '12', '13', '11', '2']
In a list I need to delete duplicate that follow each other in a list
like in this example:
[("0", "1"), ("1", "2"), ("0", "2"), ("2", "0")]
and the output I want:
["0", "1", "2", "0", "2", "0"]
I tried nothing because I have no idea what to do, maybe iterate over the list and use if index[0] == index[1].
Use a simple nested loop tracking the previous element:
l = [('0', '1'), ('1', '2'), ('0', '2'), ('2', '0')]
out = []
prev = None
for t in l:
for x in t:
if x != prev:
out.append(x)
prev = x
print(out)
Output: ['0', '1', '2', '0', '2', '0']
If you really want a list with a single tuple:
out = [tuple(out)]
Output: [('0', '1', '2', '0', '2', '0')]
you need to flatten your list first (i do that with chain(*lst)) and then you could use groupby in order to skip consecutive duplicates:
from itertools import chain, groupby
lst = [('0', '1'), ('1', '2'), ('0', '2'), ('2', '0')]
ret = [item for item, _ in groupby(chain(*lst))]
print(ret) # ['0', '1', '2', '0', '2', '0']
You can do this in several successive steps (which could actually be merged):
tuplist = [('0', '1'), ('1', '2'), ('0', '2'), ('2', '0')]
# unpacking tuples
list2 = []
for t in tuplist:
list2.extend(t) #shorter way of doing list2 += [t[0], t[1]]
# removing duplicates
list3 = [list2[0]]
for i in list2[1:]:
if i != list3[-1]:
list3.append(i)
# converting list3 to the desired format
list4 = [tuple(list3)]
I have a following problem. I would like to convert dataframe into list of tuples based on a category. See simple code below:
data = {'product_id': ['5', '7', '8', '5', '30'], 'id_customer': ['1', '1', '1', '3', '3']}
df = pd.DataFrame.from_dict(data)
#desired output is:
result = [('5', '7', '8'), ('5', '30')]
how can I do it please? This question did not help me: Convert pandas dataframe into a list of unique tuple
Use GroupBy.agg with tuple like:
print (df.groupby('id_customer', sort=False)['product_id'].agg(tuple).tolist())
print (df.groupby('id_customer', sort=False)['product_id'].apply(tuple).tolist())
print (list(df.groupby('id_customer', sort=False)['product_id'].agg(tuple)))
print (list(df.groupby('id_customer', sort=False)['product_id'].apply(tuple)))
[('5', '7', '8'), ('5', '30')]
Use groupby.agg:
>>> [tuple(v) for _, v in df.groupby('id_customer')['product_id']]
[('5', '7', '8'), ('5', '30')]
>>>
So I have this tricky dictionary of tuples which I want to filter based on the first occurrence of the informative flag in the value elements. If the flag (which is the element occupying the first position of the tuple) is observed in other keys I will only retain only the first key-value pair in which it occurs and subsequent key-value pairs which contain the flag would be skipped.
old_dict = {'abc':[('abc', '1', '5'), ('def', '1', '5'), ('abcd', '2', '5')],
'def':[('abc', '2', '5'), ('def', '1', '5'), ('abcd', '1', '5')],
'ghi':[('ghi', '1', '5'), ('jkl', '1', '4'), ('mno', '2', '4')]}
I have struggled with a lot of attempts and this latest attempt does not produce anything meaningful.
flgset = set()
new_dict = {}
for elem, tp in old_dict.items():
for flg in tp:
flgset.add(flg[0])
counter = 0
for elem, tp in old_dict.items():
for (item1, item2, item3) in tp:
for flg in flgset:
if flg == item1:
counter = 1
new_dict[elem] = [(item1, item2, item3)]
break
Expected results should be:
new_dict = {'abc':[('abc', '1', '5'), ('def', '1', '5'), ('abcd', '2', '5')],
'ghi':[('ghi', '1', '5'), ('jkl', '1', '4'), ('mno', '2', '4')]}
Thanks in advance.
If i get you correctly, the following should do what you want:
flgset = set()
new_dict = {}
for k, tuple_list in old_dict.items():
# if the key is not in flgset, just keep the k, tuple_list pair
if k not in flgset:
new_dict[k] = tuple_list
# update the elements into flgset
# item in this case is ('abc', '2', '5'),
# since you only want to add the first element, use item[0]
for item in tuple_list:
flgset.add(item[0])
Output as such:
new_dict = {'abc': [('abc', '1', '5'), ('def', '1', '5'), ('abcd', '2', '5')],
'ghi': [('ghi', '1', '5'), ('jkl', '1', '4'), ('mno', '2', '4')]}
flgset = {'abc', 'abcd', 'def', 'ghi', 'jkl', 'mno'}
Others may have more efficient ways to do this, but here's one solution that incorporates your intuitions that you need to loop over old_dict items and use a set:
for key, val in old_dict.items():
if val[0][0] not in set([v[0][0] for v in new_dict.values()]):
new_dict.update({key: val})
Here's a brief explanation of what's going on: First, val[0][0] is the "informative flag" from your dictionary entry (i.e. the first item of the first tuple in the entry list). set([v[0][0] for v in new_dict.values()]) will give you the unique values of that flag in your new dictionary. The inner part is a list comprehension to get all the "flags" and then set will give a unique list. The last line just uses the update method to append to it.
REVISED ANSWER
#VinayPai raises two important issues below in the comments. First, this code is inefficient because it reconstructs the test set each time. Here's the more efficient way he suggests:
flag_list = set()
for key, val in old_dict.items():
if val[0][0] not in flag_list:
new_dict.update({key: val})
flag_list.add(val[0][0])
The second issue is that this will produce inconsistent results because dictionaries are not ordered. One possible solution is to use an OrderedDict. But as #SyntaxVoid suggests, this is only necessary if you're using Python3.5 or earlier (here is a great answer discussing the change). If you can create your data in this fashion, it would solve the problem:
from collections import OrderedDict
old_dict = OrderedDict{'abc':[('abc', '1', '5'), ('def', '1', '5'), ('abcd', '2', '5')],
'def':[('abc', '2', '5'), ('def', '1', '5'), ('abcd', '1', '5')],
'ghi':[('ghi', '1', '5'), ('jkl', '1', '4'), ('mno', '2', '4')]}
In my attempt, I have a list: "stuff" that is supposed to be iterated over recursively to find all possible combinations. It does this by trying to recurse on all items except the first, trying to recurse on all items except the [1] index (rollover), and finally iterating over all items except the [2] index (ollie).
stuff = ['1','2','3','4','5']
def rollOver(aL):
neuList = []
neuList.append(aL[0])
neuList.extend(aL[2:])
return neuList
def ollie(aL):
neuList = []
neuList.extend(aL[0:1])
neuList.extend(aL[3:])
return neuList
def recurse(info):
try:
if len(info) == 3:
print(info)
if len(info) > 1:
recurse(info[1:])
recurse(rollOver(info))
recurse(ollie(info))
except:
l = 0
recurse(stuff)
I manually tried this method on paper and it seemed to work. However, in the code I get the results:
['3', '4', '5']
['2', '4', '5']
['3', '4', '5']
['1', '4', '5']
['1', '4', '5']
1, 3, 5 should be a listed possibility, but it doesn't show up, which leads me to think I've done something wrong.
One way to do this is via the itertools package:
from itertools import combinations
stuff = ['1','2','3','4','5']
for i in combinations(stuff, 3):
print(i)
Which gives you the desired output:
('1', '2', '3')
('1', '2', '4')
('1', '2', '5')
('1', '3', '4')
('1', '3', '5')
('1', '4', '5')
('2', '3', '4')
('2', '3', '5')
('2', '4', '5')
('3', '4', '5')
Alternatively, if you want to code this yourself in a recursive fashion, you could implement your own function as follows:
def combs(stuff):
if len(stuff) == 0:
return [[]]
cs = []
for c in combs(stuff[1:]):
cs += [c, c+[stuff[0]]]
return cs
I'll leave it to you to edit this function to only return results of a given size.