Python list concatenation logic - python

I was trying to concatenate two lists, which are 'Names' and 'Ages'.
But I wanted to do that with appending their index of [i+1] each time to another list.
So instead of ['John', '17', 'Mike', '21'], My goal was that each pair has a different index, and were a list element.Like that --> [['John', '17'], ['Mike', '21']]
(Note: I know I can do that with zip() function, this is for practice)
So I ended up with that code -->
names = ['Ana', 'John', 'Bob', 'Mike', 'July']
ages = ['17', '22', '33', '8', '76']
a = []
b = []
for i in range(len(names)):
a.append(names[i])
a.append(ages[i])
b.append([] + a)
a.clear()
print(b)
Output --> [['Ana', '17'], ['John', '22'], ['Bob', '33'], ['Mike', '8'], ['July', '76']]
So as you can see I managed to do that, but the weird thing is that line b.append([] + a). I got what I want accidently, when I type b.append(a) it returns empty b list.
But by following the path in the attached code, I'm accomplishing what I'm trying to do. Can anybody explain why this is working ? I could not catch it.
Thanks in advance.

Adding prints in the code shows that b gets 'cleared' after the loop, and it was not storing the correct information inside the loop. It is essentially copies of the same a:
names = ['Ana', 'John', 'Bob', 'Mike', 'July']
ages = ['17', '22', '33', '8', '76']
a = []
b = []
for i in range(len(names)):
a.append(names[i])
a.append(ages[i])
print(a)
b.append(a)
print(b)
a.clear()
print(b)
['Ana', '17']
[['Ana', '17']]
['John', '22']
[['John', '22'], ['John', '22']]
['Bob', '33']
[['Bob', '33'], ['Bob', '33'], ['Bob', '33']]
['Mike', '8']
[['Mike', '8'], ['Mike', '8'], ['Mike', '8'], ['Mike', '8']]
['July', '76']
[['July', '76'], ['July', '76'], ['July', '76'], ['July', '76'], ['July', '76']]
[[], [], [], [], []]
This is because lists are mutable in python. When you clear it, the data b is pointing to gets removed as well. When you do []+a, you are creating a new list which is not a reference to a any more. By changing the code this way you can get what you want:
names = ['Ana', 'John', 'Bob', 'Mike', 'July']
ages = ['17', '22', '33', '8', '76']
b = []
for i in range(len(names)):
a = []
a.append(names[i])
a.append(ages[i])
b.append(a)
print(b)
To help you understand what I mean by mutable, see the following example:
a = ['some data']
b = [a]
print(b)
a.clear()
print(b)
[['some data']]
[[]]
And this is why a+[] works:
a = ['some data']
b = [a+[]]
print(b)
a.clear()
print(b)
[['some data']]
[['some data']]

if both the list have same no of elements then you can use zip() function.
Note: The zip() function will only iterate till the smallest list passed.
list1=[]
for x,y in zip(names,ages):
list1.append([x,y])
print(list1)

Following is my solution using a list comprehension.
names = ['Ana', 'John', 'Bob', 'Mike', 'July']
ages = ['17', '22', '33', '8', '76']
new_list = [ [names[i], ages[i]] for i in range(len(names))]
print(new_list)

names = ['Ana', 'John', 'Bob', 'Mike', 'July']
ages = ['17', '22', '33', '8', '76']
a = []
b = []
for i in range(len(names)):
a.append(names[i])
a.append(ages[i])
b.append([]+a)
a.clear()
print(b)
According to your code b.append([]+a)
it is concatenation every time with array.if you checked with print statement like this
for i in range(len(names)):
a.append(names[i])
a.append(ages[i])
print("=>",a)
then show you output is
=> ['Ana', '17']
=> ['John', '22']
=> ['Bob', '33']
=> ['Mike', '8']
=> ['July', '76']
so that when you add b.append([]+a)
we understand more clearly for now
b = []
when we try
b.append([]+a)
it's mean above array concatenate the many arrays into one array .
I think you solve your problem easily when you using
zip() for iteration.
myList=[]
for a,b in zip(names,ages):
list.append([a,b])
print(myList)
output:
[['Ana', '17'], ['John', '22'], ['Bob', '33'], ['Mike', '8'], ['July', '76']]

I would use zip within a list comprehension:
names = ['Ana', 'John', 'Bob', 'Mike', 'July']
ages = ['17', '22', '33', '8', '76']
b = [[name,age] for name, age in zip(names,ages)]

you can use zip and list to write this in a single line of code:
result = list(zip(names, ages))

Related

Merge list for 2d list, its separating correctly but when it comes back all together it is wrong,

Here is my code, the code is usual merge sort but with my print statements showing each step, the only issue I have is when it comes back all together there are duplicate values and stuff of that matter
def mergeSort(list):
if len(list) > 1:
mid = len(list) // 2
left = list[:mid]
right = list[mid:]
print("left:\n"+str(left).replace("],","]\n"))
print("right:\n"+str(right).replace("],","]\n"))
print("")
#recursion
mergeSort(left)
mergeSort(right)
i = j = k = 0
while i < len(left) and j < len(right):
if left[i][0] < right[j][0]:
list[k].append(left[i][0])
i += 1
else:
list[k].append(right[j][0])
j += 1
k += 1
while i < len(left):
list[k].append(left[i][0])
i += 1
k += 1
while j < len(right):
list[k].append(right[j][0])
j += 1
k += 1
This is the output
left:
[['21', 'John', 'S.', '$100.00']
['20', 'Mark', 'Z.', '$123.00']
['18', 'Susan', 'K.', '$0.00']]
right:
[['25', 'Paul', 'A.', '$0.00']
['44', 'Elvis', 'P.', '$4,000.00']
['8', 'Lucas', 'L.', '$5.00']]
left:
[['21', 'John', 'S.', '$100.00']]
right:
[['20', 'Mark', 'Z.', '$123.00']
['18', 'Susan', 'K.', '$0.00']]
left:
[['20', 'Mark', 'Z.', '$123.00']]
right:
[['18', 'Susan', 'K.', '$0.00']]
left:
[['25', 'Paul', 'A.', '$0.00']]
right:
[['44', 'Elvis', 'P.', '$4,000.00']
['8', 'Lucas', 'L.', '$5.00']]
left:
[['44', 'Elvis', 'P.', '$4,000.00']]
right:
[['8', 'Lucas', 'L.', '$5.00']]
[['21', 'John', 'S.', '$100.00', '20', '21']
['20', 'Mark', 'Z.', '$123.00', '18', '18', '20']
['18', 'Susan', 'K.', '$0.00', '20', '21', '18']
['25', 'Paul', 'A.', '$0.00', '25', '25']
['44', 'Elvis', 'P.', '$4,000.00', '44', '44', '44']
['8', 'Lucas', 'L.', '$5.00', '8', '8', '8']]
I was able to merge sort if it was just an array with the same "first column values" and thats how I know it is separating correctly. I just cannot see where I went wrong with my function, maybe im just blind.
I found three mistakes in your code.
Never ever call a variable list in python
Find another name for the argument of your function. list is already the name of the class that handles everything related to lists in python. Giving this name to another object leads to unforeseen trouble. Instead, call your variable l, or ll, or myList, or whatever other name you can think of.
You are comparing strings instead of numbers
By default, strings are compared according to lexicographical order. Thus, '2' > '18', because '2' begins with the character '2' whereas '18' begins with the character '1'. This is most likely not what you want. You can either modify your list before sorting to replace those strings with numbers; or you can replace your test if left[i][0] < right[j][0]: with if int(left[i][0]) < int(right[j][0]):
Your merge function is appending the wrong things at the wrong places
Let me illustrate the effect of the line list[k].append(left[i][0]) using python's interactive interpreter:
>>> left = [['21', 'John', 'S.', '$100.00'],['20', 'Mark', 'Z.', '$123.00'],['18', 'Susan', 'K.', '$0.00']]
>>> myList = [['21', 'John', 'S.', '$100.00'],['20', 'Mark', 'Z.', '$123.00'],['18', 'Susan', 'K.', '$0.00'],['25', 'Paul', 'A.', '$0.00'],['44', 'Elvis', 'P.', '$4,000.00'],['8', 'Lucas', 'L.', '$5.00']]
>>> i = 0
>>> k = 0
>>> myList[k].append(left[i][0])
>>> myList
[['21', 'John', 'S.', '$100.00', '21'],
['20', 'Mark', 'Z.', '$123.00'],
['18', 'Susan', 'K.', '$0.00'],
['25', 'Paul', 'A.', '$0.00'],
['44', 'Elvis', 'P.', '$4,000.00'],
['8', 'Lucas', 'L.', '$5.00']]
What happened? myList[k] is an element of myList: since myList is a list of lists, in this case it's the list corresponding to John. left[i] is the first element of left; since left is a list of lists, in this case it's the list corresponding to John. Finally, left[i][0] is the first element of John's list, which is the string '21'. So you are appending the element '21' to the list ['21', 'John', 'S.', '$100.00'], and this results in John's list in myList becoming ['21', 'John', 'S.', '$100.00', '21'].
How to fix it? Simply write myList[k] = left[i] instead. This will replace the kth element of myList with the ith element of left, which is what you want.

Create dictionary of dictionaries of lists in one line

Any way to create dictionary of dictionaries of lists in one line?
names = ['alex', 'ben', 'coby']
age = ['20', '30', '40', '50']
name_age = {n: {} for n in names}
for n in names:
name_age[n] = {a: {} for a in age}
Nesting such as below does not work.
name_age = {n: {{a: {} for a in age}} for n in names}
The fastest way of constructing a dictionary based on two lists is iterating them at the same time with zip. This will work:
names = ['alex', 'ben', 'coby']
age = ['20', '30', '40', '50']
name_age = dict(zip(names, age))
print(name_age)
>>> {'alex': '40', 'ben': '50', 'coby': '20'}
names = ['alex', 'ben', 'coby']
ages = ['20', '30', '40', '50']
result = { names[index]:ages[index] for index in range(len(names)) }
print(result)
{'alex': '20', 'ben': '30', 'coby': '40'}

combine two lists in a list of dictionaries into one

I want to combine the list of ages of the groups which are having a repeated name...
My code:
dic1 = {'g1': ['45', '35', '56', '65'], 'g2': ['67', '76'], 'g3':['8', '96']}
dic2 = {'g1': ['akshay', 'swapnil', 'parth','juhi'], 'g2': ['megha', 'varun'], 'g3': ['gaurav', 'parth']}
for key2,name_list in dic2.items():
for name in name_list:
if name=='parth':
for key1,age_list in dic1.items():
if key1==key2:
print(age_list)
The output is:
['45', '35', '56', '65']
['8', '96']
I want the output as:
['45', '35', '56', '65', '8', '96']
Can someone help me with this?
there's more pythonic than that, you need to chain the lists. Also, no need for so many loops. A one-liner should do.
dic1 = {'g1': ['45', '35', '56', '65'], 'g2': ['67', '76'], 'g3':['8', '96']}
dic2 = {'g1': ['akshay', 'swapnil', 'parth','juhi'], 'g2': ['megha', 'varun'], 'g3': ['gaurav', 'parth']}
import itertools
result = list(itertools.chain.from_iterable(dic1[k] for k,v in dic2.items() if 'parth' in v))
>>> result
['45', '35', '56', '65', '8', '96']
A variant without itertools would be:
result = [x for k,v in dic2.items() if 'parth' in v for x in dic1[k]]
With a dict of sets instead of a dict of lists:
dic2 = {'g1': {'akshay', 'swapnil', 'parth','juhi'}, 'g2': {'megha', 'varun'}, 'g3': {'gaurav', 'parth'}}
those turn your O(N**3) algorithm into a O(N) algorithm (because in lookup in a list is O(N) but O(1) in a set).
If you have a missing key, just replace dic1[k] by dic1.get(k,[]) or even dic1.get(k) or [].
You could either use itertools as mentioned in other answers, or just simplify your own code.
There is no need to have a three layer nested for loop. As python only allows
unique keys, you could eliminate the innermost for loop like so:
output_list = []
for key, name_list in dic2.items():
if "parth" in name_list:
output_list += dic1[key]
print(output_list)
As and when you get the required age list which is to be displayed, add it to the output_list with a simple +=.
Though the above code is easier to understand, I recommend using itertools.

removing whitespace and \n from list in python?

list1= ['34 5\n', '67 37\n', '40 33\n', '99 100\n', '55 22']
the above is the list that i have, how can i make that to
['34','5','67','37','40','33','99','100','55','22']
I want to remove the white space and '\n'. rstrip , strip , replace have been tried but none of the worked
list1.rstrip('\n')
list1.strip('\n')
list1.remove('\n')
Use a pair of nested list comprehensions, the inner of which splits the strings on whitespace and the outer of which merges the nested lists together.
>>> list1= ['34 5\n', '67 37\n', '40 33\n', '99 100\n', '55 22']
>>> [x for sublist in [s.split() for s in list1] for x in sublist]
['34', '5', '67', '37', '40', '33', '99', '100', '55', '22']
Or, if this isn't to your liking, do it with loops instead. (This is probably clearer than a nested list comprehension, come to think of it.)
>>> result = []
>>> for s in list1:
for num in s.split():
result.append(num)
>>> result
['34', '5', '67', '37', '40', '33', '99', '100', '55', '22']
from itertools import chain
list2 = list(chain.from_iterable(map(str.split,list1)))
you can break this down to be somewhat more readable
flatten_list = chain.from_iterable
list_of_splits = map(str.split,list1) #essentially [s.split() for s in list1]
list2 = flatten_list(list_of_splits)
list2 = []
for item1 in list1:
split_list = " ".split(item1)
for item2 in split_list:
list2.append(item2.rstrip())

how to create a sub list for a specific string in a nested list

I have Python nested list that I'm trying to organize and eventually count number of occurrences. The nested list looks like:
[['22', '1'], ['21', '15'], ['11', '3'], ['31', '4'], ['41', '13'],...]
The first I want to do is create a sublist that only contains '1' corresponding to the second item in the nested list. I was able to do this by the following command:
Subbasin_1 = []
Subbasin_1.append([x for x in Subbasins_Imp if x[1] == '1'])
print Subbasin_1
Giving these results, which are correct:
[['21', '1'], ['21', '1'], ['21', '1'], ['21', '1'], ['22', '1'],...]
Now I want to create another sublist that will give me all the '21' in the each nested list for Subbasin_1. When I use the same line of script, but change the appropriate items, I get an empty list. Not sure what is going on...?
OS_Count1 = []
OS_Count1.append([x for x in Subbasin_1 if x[0] == '21'])
print OS_Count1
Result is [[]] ??? What's the difference between the two?
Thanks for any help...
I don't believe that your
[['21', '1'], ['21', '1'], ['21', '1'], ['21', '1'], ['22', '1'],...]
line could be produced by the code you gave. Your Subbasin_1.append line appends a list to the empty list Subbasin_1, so you should get something like
[[['22', '1'], ['21', '1']]]
with one extra level of nesting.
If you avoid the unnecessary construction of an empty list + append, you should get what you want:
>>> Subbasins_Imp = [['22', '1'], ['21', '15'], ['11', '3'], ['31', '4'], ['41', '13'], ['21', '1']]
>>>
>>> Subbasin_1 = [x for x in Subbasins_Imp if x[1] == '1']
>>> print Subbasin_1
[['22', '1'], ['21', '1']]
>>> OS_Count1 = [x for x in Subbasin_1 if x[0] == '21']
>>> print OS_Count1
[['21', '1']]
Alternatively, you could simply replace append by extend. I don't recommend this, but it might help you to see what's happening:
>>> Subbasins_Imp = [['22', '1'], ['21', '15'], ['11', '3'], ['31', '4'], ['41', '13'], ['21', '1']]
>>>
>>> Subbasin_1 = []
>>> Subbasin_1.extend([x for x in Subbasins_Imp if x[1] == '1'])
>>> print Subbasin_1
[['22', '1'], ['21', '1']]
>>>
>>> OS_Count1 = []
>>> OS_Count1.extend([x for x in Subbasin_1 if x[0] == '21'])
>>> print OS_Count1
[['21', '1']]
Your list comprehension [x for x in Subbasins_Imp if x[1] == '1'] creates a list by itself, which means when you append that list to Subbasin_1, you end up with a doubly nested list.
Compare:
sub_imp = [['22', '1'], ['21', '15'], ['11', '3'], ['31', '4'], ['41', '13']]
sub_1 = [x for x in sub_imp if x[1] == '1']
sub_2 = []
sub_2.append([x for x in sub_imp if x[1] == '1'])
print(sub_1)
print(sub_2)
Running your code I obtained a triple nested list....
Sub = [[['21','1'],....]]
Instead of doing:
Subbasin_1 = []
Subbasin_1.append([x for x in Sub if x[1]=='1'])
Simple do the list comprehension :
Subbasin_1 = [x for x in Sub if x[1] == '1']
This will give you the result you are expecting.
There is no difference which implies Subbasin_1 might be empty at the time of the call or doesn't contain the data you think it does. It might also be that Subbasin_1 is nested 3 layers deep, not 2.

Categories

Resources