Appending an int key in a dictionary - python-3.x

I am trying to create a dictionary from the following lists:
link_i = [1, 1, 3, 3, 3, 4, 4, 5, 5, 6]
link_j = [2, 3, 1, 2, 5, 5, 6, 6, 4, 4]
link_i = [1, 1, 3, 3, 3, 4, 4, 5, 5, 6]
link_j = [2, 3, 1, 2, 5, 5, 6, 6, 4, 4]
nodes = [1, 2, 3, 4, 5, 6]
# Creating a dictionary containing nodes and their incoming links:
out_dict = {}
for i in nodes:
for j in range(0,len(link_i)):
if (link_i[j] == i):
if i not in out_dict:
out_dict[i] = link_j[j]
elif i in out_dict:
out_dict[i].append(link_j[j])
However, I am not able to append the key since it has the type int. I get the error:
line 21, in <module>
out_dict[i].append(link_j[j])
AttributeError: 'int' object has no attribute 'append'
I am trying to get the output as:
{1: [2, 3], 3: [1, 2, 5], 4: [5, 6], 5: [6, 4], 6: [4]}

To keep the code simple you can use a dict comprehension and set the default value for each node to empty list. With that you don't need to check if the node is already part of the dict and you can just append the links.
link_i = [1, 1, 3, 3, 3, 4, 4, 5, 5, 6]
link_j = [2, 3, 1, 2, 5, 5, 6, 6, 4, 4]
nodes = [1, 2, 3, 4, 5, 6]
# Creating a dictionary containing nodes and their incoming links:
# fill the dict with empty lists for each node
out_dict = {node: [] for node in nodes}
for i in nodes:
for j in range(0,len(link_i)):
if (link_i[j] == i):
# append link to the list for the node
out_dict[i].append(link_j[j])
The output then looks like this:
{1: [2, 3], 2: [], 3: [1, 2, 5], 4: [5, 6], 5: [6, 4], 6: [4]}

You need to change:
if i not in out_dict:
out_dict[i] = link_j[j]
to
if i not in out_dict:
out_dict[i] = [link_j[j]]
This is because after you first add key "i" to out_dict, you are assigning it a single value which is of type int. In order to be able to add to this, later on, it needs to be a mutatable data type such as a list which does have attribute append. This doesn't fix all your problems because even with this change you still don't get your desired output but it will allow you to debug further.

Related

How to classify sub-lists of a list under a specific condition

I have a list containing sub-lists. If the differences between sub-lists are less than 0.1, I want to group these sub-lists.
import numpy as np
def difference(A, B):
difference = []
zip_object = zip(sorted(A), sorted(B))
for l1, l2 in zip_object:
difference.append(abs(l1-l2))
sum_ = 0
for i in difference:
sum_ += i
if round(sum_, 5) <=0.1:
return True
return False
aaa = [[1.001, 2, 5, 3, 5, 4, 6, 9, 10],
[2, 5, 3, 5, 4, 6.001, 9, 10, 1],
[2, 5.5, 3, 5, 4, 6.001, 9, 10, 1],
[2, 5.5, 3, 5, 4, 6.001, 9, 10.2, 1],
[2, 5, 2.999, 5, 4, 6.001, 9, 10, 1],
[2, 5.5, 2.999, 5, 4, 6.001, 9, 10.2, 1]]
AAA = []
for i in range(len(aaa)):
a = [i]
for j in range(len(aaa)):
if i < j and difference(aaa[i], aaa[j])==True:
a.append(j)
AAA.append(a)
print(AAA)
My code yields:
[[0, 1, 4], [1, 4], [2], [3, 5], [4], [5]]
But I want the result like this
[[0, 1, 4], [3, 5]]
As long as you can import numpy, here is a short solution that uses numpy
import numpy as np
aaa = [[1.001, 2, 5, 3, 5, 4, 6, 9, 10],
[2, 5, 3, 5, 4, 6.001, 9, 10, 1],
[2, 5.5, 3, 5, 4, 6.001, 9, 10, 1],
[2, 5.5, 3, 5, 4, 6.001, 9, 10.2, 1],
[2, 5, 2.999, 5, 4, 6.001, 9, 10, 1],
[2, 5.5, 2.999, 5, 4, 6.001, 9, 10.2, 1]]
# sort each row for calculating differences
aaa = np.sort(aaa,axis=1)
# calculate the difference
diff = np.sum(np.abs(aaa[:,None,:] - aaa),axis=2)
# don't need an item with itself
np.fill_diagonal(diff,1e5)
# find the pairs of rows that have a small difference
locs = np.unique(np.sort(np.where(diff <= .1 ),axis=0),axis=1).T
# get the results
res = {}
redundant = []
flattened_list = []
for pair in locs:
if pair[0] not in res.keys() and pair[0] not in redundant:
res[pair[0]] = [pair[1]]
redundant.extend(pair)
elif pair[0] in res.keys():
if pair[1] not in res[pair[0]]:
res[pair[0]].append(pair[1])
flattened_list = [[key,*val] for key,val in res.items()]
I've created a verbose program that you can adjust to your needs.
def new_difference(list1, list2):
list_length = len(list1)
list1 = sorted(list1)
list2 = sorted(list2)
total = 0
for i in range(list_length):
total += abs(list1[i] - list2[i])
return round(total, 5) <= 0.1;
def add_good_diff():
# if 0 matches with 1, create dictionary 0: [1]
# if 0 matches with 4, add to the list like so 0: [1, 4]
if not i in good_diff:
good_diff[i] = [j]
else:
good_diff[i].append(j)
def proceed_with_diff(i, j):
# let's say 0'th list matches with 1 and 4
# when we get to the next list, we don't want to compare 1 and 4
# so, check each list in good_diff. If found, return False
# which means, skip matching i and j
for item in good_diff:
if i in good_diff[item] and j in good_diff[item]:
print(f"{i} and {j} already diff'ed successfully")
return False
return True
aaa = [[1.001, 2, 5, 3, 5, 4, 6, 9, 10],
[2, 5, 3, 5, 4, 6.001, 9, 10, 1],
[2, 5.5, 3, 5, 4, 6.001, 9, 10, 1],
[2, 5.5, 3, 5, 4, 6.001, 9, 10.2, 1],
[2, 5, 2.999, 5, 4, 6.001, 9, 10, 1],
[2, 5.5, 2.999, 5, 4, 6.001, 9, 10.2, 1]]
sets = len(aaa)
good_diff = {} # stores {0: {1, 4}, 3: {5}} - successful matches
final_list = [] # is used to flatten output to [[0, 1, 4], [3, 5]]
# starts with 0'th item
for i in range(0, sets):
# compares 0'th item with 1..5
for j in range(i+1, sets):
print(f'Matching {i} and {j}')
# if i and j have been compared already, don't compare them again
# proceed_with_diff returns True a match has not been done before
if proceed_with_diff(i, j):
# if diff is within accepted value, add it to the dictionary
if new_difference(aaa[i], aaa[j]):
print(f'{i} matches {j}. Adding to good_diff')
add_good_diff()
# flatten the dictionary
# {0: [1, 4]} will become [0, 1, 4]
for item in good_diff:
final_list.append([item] + good_diff[item])
print(final_list)
When you run that, you will see the result:
[[0, 1, 4], [3, 5]]
Give it a shot.

numpy remove column by different value in batch

I want to ask how numpy remove columns in batch by list.
The value in the list corresponds to the batch is different from each other.
I know this problem can use the for loop to solve, but it is too slow ...
Can anyone give me some idea to speed up?
array (batch size = 3):
[[0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6]]
remove index in the list (batch size = 3)
[[2, 3, 4], [1, 2, 6], [0, 1, 5]]
output:
[[0, 1, 5, 6], [0, 3, 4, 5], [2, 3, 4, 6]]
Assuming the array is 2d, and the indexing removes equal number of elements per row, we can remove items with a boolean mask:
In [289]: arr = np.array([[0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6]]
...: )
In [290]: idx = np.array([[2, 3, 4], [1, 2, 6], [0, 1, 5]])
In [291]: mask = np.ones_like(arr, dtype=bool)
In [292]: mask[np.arange(3)[:,None], idx] = False
In [293]: arr[mask]
Out[293]: array([0, 1, 5, 6, 0, 3, 4, 5, 2, 3, 4, 6])
In [294]: arr[mask].reshape(3,-1)
Out[294]:
array([[0, 1, 5, 6],
[0, 3, 4, 5],
[2, 3, 4, 6]])

How to merge two array and group by key?

How to merge two array and group by key?
Example:
my_list = [3, 4, 5, 6, 4, 6, 8]
keys = [1, 1, 2, 2, 3, 5, 7]
Expected outcome:
[[1, 3, 4], [2, 5, 6], [3, 4], [5, 6], [7, 8]]
If I understand it right, the list of keys map to the list of values. You can use the zip function to iterate through two lists at the same time. Its convenient in this case. Also check up on the beautiful defaultdict functionality - we can use it to fill a list without initialising it explicitely.
from collections import defaultdict
result = defaultdict(list) # a dictionary which by default returns a list
for key, val in zip(keys, my_list):
result[key].append(val)
result
# {1: [3, 4], 2: [5, 6], 3: [4], 5: [6], 7: [8]}
You can then go to a list (but not sure why you would want to) with:
final = []
for key, val in result.items():
final.append([key] + val) # add key back to the list of values
final
# [[1, 3, 4], [2, 5, 6], [3, 4], [5, 6], [7, 8]]
I think you have to write it by your own using set() to remove duplicates, so I have made a function called merge_group
my_list = [3, 4, 5, 6, 4, 6, 8]
keys = [1, 1, 2, 2, 3, 5, 7]
def merge_group(input_list : list, input_key : list):
result = []
i = 0
while i < len(my_list):
result.append([my_list[i], keys[i]])
i += 1
j = 0
while j < len(result):
if j+1 < len(result):
check_sum = result[j] + result[j+1]
check_sum_set = list(set(check_sum))
if len(check_sum) != len(check_sum_set):
result[j] = check_sum_set
j += 1
return result
print(merge_group(my_list, keys))

How to make a new matrix from another matrix by using its first column as new's first row?

I want to use a python function or library - if any - for creating a new matrix whose first row beginning from the right-below is created by using old matrix's first column beginning from the left-top. That matrix can have different columns and rows but of course my new matrix have to have same dimension as previous one. My will is something like that:
In keeping with the brief style of the question:
In [467]: alist = [5,6,4,3,4,5,3,2,5,3,1,2,2,3,2,1,3,1,1,1]
In [468]: arr = np.array(alist).reshape(4,5)
In [469]: arr
Out[469]:
array([[5, 6, 4, 3, 4],
[5, 3, 2, 5, 3],
[1, 2, 2, 3, 2],
[1, 3, 1, 1, 1]])
In [470]: arr.reshape(5,4)
Out[470]:
array([[5, 6, 4, 3],
[4, 5, 3, 2],
[5, 3, 1, 2],
[2, 3, 2, 1],
[3, 1, 1, 1]])
In [471]: arr.reshape(5,4,order='F')
Out[471]:
array([[5, 3, 2, 1],
[5, 2, 1, 4],
[1, 3, 3, 3],
[1, 4, 5, 2],
[6, 2, 3, 1]])
In [473]: np.rot90(_)
Out[473]:
array([[1, 4, 3, 2, 1],
[2, 1, 3, 5, 3],
[3, 2, 3, 4, 2],
[5, 5, 1, 1, 6]])

python 3 add many list in one

I have several lists with the same number of elements, example:
[[1, 2, 3, 1], [3, 2, 1, 2], [3, 3, 1, 1], [...], .....etc...
I would like to get a single list containing all the items in the listed lists, example:
[1, 2, 3, 1, 3, 2, 1, 2, 3, 3, 1, 1, ..........]
How can I get this result in the simplest way possible?
I tried this way but I can not find a solution.
a = [[1, 2, 3, 1], [3, 2, 1, 2], [3, 3, 1, 1]]
b = len(a)
for n in range(b):
a[0] += a[n]
print(a[0])
result:
[1, 2, 3, 1, 1, 2, 3, 1]
[1, 2, 3, 1, 1, 2, 3, 1, 3, 2, 1, 2]
[1, 2, 3, 1, 1, 2, 3, 1, 3, 2, 1, 2, 3, 3, 1, 1]
I would only use the last list produced without the repetition of the first list, but I can not correct it and extrapolate it.
Thank you.
A straightforward solution would use extend method of a list.
a = [[1, 2, 3, 1], [3, 2, 1, 2], [3, 3, 1, 1]]
result = []
for aa in a:
result.extend(aa)
I hope you will find Python's itertools interesting for this as well.
from itertools import chain
a = [[1, 2, 3, 1], [3, 2, 1, 2], [3, 3, 1, 1]]
result = list(chain(*a))
*a is basically unpacking the list for you.
Python has a reduce() function that can be used like this:
a = [[1, 2, 3, 1], [3, 2, 1, 2], [3, 3, 1, 1]]
import functools
functools.reduce(lambda x, y: x+y, a)
Result:
[1, 2, 3, 1, 3, 2, 1, 2, 3, 3, 1, 1]
This may be less efficient than modifying an element in-place, as in the question. If you want to keep using that, the simple thing to do is to start with an empty list rather than re-using a[0]:
result = []
for e in a:
result += e
print(result)

Resources