Suppose that I am given a list of strings, e.g. list = ['a', 'b', 'c']. I am also given a list of 'continuation strings', e.g. continuations = ['d', 'f'], and I want to form a list of all possible sequences formed by combining the original list with a continuation letter. In this example, I want to obtain the list of lists: new_list = [['a', 'b', 'c', 'd'], ['a', 'b', 'c', 'f']]. To do this, I tried
new_list = []
for element in continuations:
# Make a copy of the original list
copy = list
# Add a continuation letter to the original list
possible_sequence = copy.append(element)
# Add the new list to the list of lists
new_list.append(possible_sequence)
But this generates [None, None]... Can anyone explain what is wrong with my code?
# it is a bad practice to shadows built-in name, so I changed 'list' name to 'abc_list'
abc_list = ['a', 'b', 'c']
continuation = ['d', 'f']
print([abc_list + [x] for x in continuation])
Output: [['a', 'b', 'c', 'd'], ['a', 'b', 'c', 'f']]
CODE
main_list = ['a', 'b', 'c']
continuations = ['d', 'f']
new_list = []
for element in continuations:
temp_list = main_list.copy()
temp_list.append(element)
new_list.append(temp_list)
print(new_list)
OUTPUT
[['a', 'b', 'c', 'd'], ['a', 'b', 'c', 'f']]
Here's how I would do it.
create a list to store the possible sequences
iterate through the continuation list
copy the original list
append the continuation letter to the copied list
append the copied list to the possible list
def combine_list(list_, cont_list):
# create a list to store the possible sequences
possible_list = []
# iterate through the continuation list
for j in cont_list:
# copy the original list
l2 = list_.copy()
# append the continuation letter to the copied list
l2.append(j)
# append the copied list to the possible list
possible_list.append(l2)
return possible_list
l = ['a', 'b', 'c']
c = ['d', 'f']
print(combine_list(l, c))
Output:
[['a', 'b', 'c', 'd'], ['a', 'b', 'c', 'f']]
Edit
What's wrong with your code?
If you want to copy a list you need to it with list.copy(). If you just do copy = list you are not creating a new list object. if you make changes in copy all changes will apply to list also.
The list.append(element) function does not return a list object it returns None that's why your result looks like this [None, None] you appended None twice.
In Python, append modifies the list it is called on and doesn't return anything (technically it returns None, which is why you ended up with a list full of None). That means that you cannot store the result of append in a variable.
my_list = []
foo = my_list.append(1)
print(foo) # Prints 'None' because that's all that append returns
print(my_list) # Prints '[1]' because the value got added to the original list by append
This is the big difference between lists and strings in Python that beginners sometimes get confused about. Strings are immutable which means they cannot be changed. So methods such as replace return a new string, because they cannot modify the original string. Lists, on the other hand, are mutable, meaning they can be modified. So methods on lists such as append or pop modify the list they are called on rather than returning a new one.
my_string = "Python"
# Needs to be stored in a new variable,
# the original string cannot be modified
new_string = my_string.replace("n", "k")
print(my_string) # Still the original value, Python
print(new_string) # The new modified value, Pythok
my_list = [1, 2]
my_list.append(3) # Modified the list itself, no need to store anything new
print(my_list) # [1, 2, 3]
Also, note that it is an extremely bad idea to call one of your lists list as list is a keyword in Python. (It is used to construct new lists, e.g. list(range(10)) creates a list [0, 1, ..., 9]).
Related
my_list = ['a', 'b', 'a', 'd', 'e', 'f']
my_list_2 = ['a', 'b', 'c']
The common items are:
c = ['a', 'b', 'a']
The code:
for e in my_list:
if e in my_list_2:
c.append(e)
...
If the my_list is long, this would be very inefficient. If I convert both lists into two sets, then use set's intersection() function to get the common items, I will lose the duplicates in my_list.
How to deal with this efficiently?
dict is already a hashmap, so lookups are practically as efficient as a set, so you may not need to do any extra work collecting the values - if it wasn't, you could pack the values into a set to check before checking the dict
However, a large improvement may be to make a generator for the values, rather than creating a new intermediate list, to iterate over where you actually want the values
def foo(src_dict, check_list):
for value in check_list:
if value in my_dict:
yield value
With the edit, you may find you're better off packing all the inputs into a set
def foo(src_list, check_list):
hashmap = set(src_list)
for value in check_list:
if value in hashmap:
yield value
If you know a lot about the inputs, you can do better, but that's an unusual case (for example if the lists are ordered you could bisect, or if you have a huge verifying list or very very few values to check against it you may find some efficiency in the ordering and if you make a set)
I am not sure about time efficiency, but, personally speaking, list comprehension would always be more of interest to me:
[x for x in my_list if x in my_list_2]
Output
['a', 'b', 'a']
First, utilize the set.intersection() method to get the intersecting values in the list. Then, use a nested list comprehension to include the duplicates based on the original list's count on each value:
my_list = ['a', 'b', 'a', 'd', 'e', 'f']
my_list_2 = ['a', 'b', 'c']
c = [x for x in set(my_list).intersection(set(my_list_2)) for _ in range(my_list.count(x))]
print(c)
The above may be slower than just
my_list = ['a', 'b', 'a', 'd', 'e', 'f']
my_list_2 = ['a', 'b', 'c']
c = []
for e in my_list:
if e in my_list_2:
c.append(e)
print(c)
But when the lists are significantly larger, the code block utilizing the set.intersection() method will be significantly more efficient (faster).
sorry for not reading the post carefully and now it is not possible to delete.. however, it is an attempt for solution.
c = lambda my_list, my_list_2: (my_list, my_list_2, list(set(my_list).intersection(set(my_list_2))))
print("(list_1,list_2,duplicate_items) -", c(my_list, my_list_2))
Output:
(list_1,list_2,duplicate_items) -> (['a', 'b', 'a', 'd', 'e', 'f'], ['a', 'b', 'c'], ['b', 'a'])
or can be
[i for i in my_list if i in my_list_2]
output:
['a', 'b', 'a']
I'm learning python and I have been trying to make an automatic list of lists. For example:
The next list, which I have to split to get a list of separated letters, and then join them again to make a two lists of separated letters
lists=[['a,b,c,h'],['d,e,f,g']]
print('list length', len(lists))
splited=[]
splited1=lists[0][0].split(',')
print(splited1) #['a', 'b', 'c', 'h']
splited2=lists[1][0].split(',')
print(splited2) #['d', 'e', 'f', 'g']
listcomb=[splited1,splited2]
print(listcomb) #[['a', 'b', 'c', 'h'], ['d', 'e', 'f', 'g']]
This is what I want to get, a list that have 2 lists, but in the case I have to get more lists inside that list i want to make it automatic with a for loop.
My try, but it didn't work
listcomb2=zip(splited1,splited2)
print(listcomb2)
sepcomb = list()
print(type(sepcomb))
for x in range(len(lists)):
sep=lists[x][0].split(',')
sepcomb[x]=[sep]
print(sepcomb)
I'm having problems with splitting the letters and then joining them in a new list. Pls help
Make some tweak in your code. As we can see lenght of sepcomb is 0 so use append method to avoid this problem. As sepcomb[x]=[sep] is is assignment to x-index but it x index doesn't exist so, it will raise error
change:
for x in range(len(lists)):
sep=lists[x][0].split(',')
sepcomb[x]=[sep]
to
for x in range(len(lists)):
sep=lists[x][0].split(',')
sepcomb.append(sep)
Method-2
sepcomb = list(i[0].split(',') for i in lists)
You can simply do the following:
final=[splinted1]+[splinted2]
Or a better way directly from the lists variable would be:
final=[value[0].split(',') for value in lists]
Here you go:
lists = [['a,b,c,h'],['d,e,f,g']]
listcomb = []
for each in lists:
splited = each[0].split(',')
listcomb.append(splited)
print(listcomb)
Edited:
This should be the exact same thing I am doing with my code below, but simplified.
I'm replacing values in a nested list. The first 3 values change correctly, but the last 3 replace with the same value. If I run this simplified code, it outputs correctly.. I can't see how this would be any different than my actual code at the bottom.
string = [['A', 'B', 'C'],
['A', 'B', 'C'],
['A', 'B', 'C'],
['D', 'E', 'F'],
['D', 'E', 'F'],
['D', 'E', 'F']]
string[0][2] = 'X'
string[1][2] = 'Y'
string[2][2] = 'Z'
string[3][2] = 'X'
string[4][2] = 'Y'
string[5][2] = 'Z'
for i in string:
print(i)
['A', 'B', 'X']
['A', 'B', 'Y']
['A', 'B', 'Z']
['D', 'E', 'Z']
['D', 'E', 'Z']
['D', 'E', 'Z']
Will someone please let me know what is going wrong here? I'm replacing string values within the list below. Everything works fine for the first 5 changes... However my last 5 values are each being replaced by the same value.
self.seq_string[67][1] = 'Sequence_Images/40_1.jpg'
self.seq_string[106][2] = 'Sequence_Images/39_6.jpg'
self.seq_string[131][1] = 'Sequence_Images/38_6.jpg'
self.seq_string[175][1] = 'Sequence_Images/37_5.jpg'
self.seq_string[177][2] = 'Sequence_Images/1_2.jpg'
self.seq_string[87][2] = 'Sequence_Images/40_1.jpg'
self.seq_string[116][2] = 'Sequence_Images/39_6.jpg'
self.seq_string[171][2] = 'Sequence_Images/38_6.jpg'
self.seq_string[180][2] = 'Sequence_Images/37_5.jpg'
self.seq_string[184][2] = 'Sequence_Images/1_2.jpg'
print(self.seq_string[67])
print(self.seq_string[106])
print(self.seq_string[131])
print(self.seq_string[175])
print(self.seq_string[177])
print('\n')
print(self.seq_string[87])
print(self.seq_string[116])
print(self.seq_string[171])
print(self.seq_string[180])
print(self.seq_string[184])
The first changed values in this list comes out just fine:
['Sequence_Images/16_3.jpg', 'Sequence_Images/40_1.jpg']
['Sequence_Images/33_2.jpg','Sequence_Images/9_4.jpg','Sequence_Images/39_6.jpg']
['Sequence_Images/16_3.jpg', 'Sequence_Images/38_6.jpg']
['Sequence_Images/33_2.jpg', 'Sequence_Images/37_5.jpg']
['Sequence_Images/33_2.jpg', 'Sequence_Images/9_4.jpg', 'Sequence_Images/1_2.jpg']
...But these ones all replace it with the same value. It's okay that the first items are all the same - I'm only replacing the last value on each:
['Sequence_Images/16_3.jpg', 'Sequence_Images/35_5.jpg', 'Sequence_Images/1_2.jpg']
['Sequence_Images/16_3.jpg', 'Sequence_Images/35_5.jpg', 'Sequence_Images/1_2.jpg']
['Sequence_Images/16_3.jpg', 'Sequence_Images/35_5.jpg', 'Sequence_Images/1_2.jpg']
['Sequence_Images/16_3.jpg', 'Sequence_Images/35_5.jpg', 'Sequence_Images/1_2.jpg']
['Sequence_Images/16_3.jpg', 'Sequence_Images/35_5.jpg', 'Sequence_Images/1_2.jpg']
Following on #Błotosmętek's comment, the problem may well be that you only have one list that is being pointed to by many different sublists. With a bit of code to explain this, let's imagine I have the following code (basically same as you have I guess):
# I create two sublists to be used when I want the same information
# in two different rows of my global list
l1 = ['A','B','C']
l2 = ['C','D','E']
# I now create a global list using my sublist
l = [l1, l1, l2, l2]
Now both l[0] and l[1] point to the exact same object l1. When you access l[0] and make some changes, Python is actually using it as a pointer to the physical list l1 and makes changes there; therefore when you then want to access l[1], you will see the changes that you made on l[0].
That's because Python doesn't like wasting time copying a full massive list into a new variable if it's not necessary. If you want Python to actually copy a list in a new variable rather than create a pointer to the list, you need to explicitly do the copy, using copy.deepcopy:
import copy
l = [copy.deepcopy(l1),
copy.deepcopy(l1),
copy.deepcopy(l2),
copy.deepcopy(l2)]
Now your list l contains 4 independent lists, and not 4 pointers to 2 physical lists.
I'm new to programming in general, so looking to really expand my skills here. I'm trying to write a script that will grab a list of strings from an object, then order them based on a template of my design. Any items not in the template will be added to the end.
Here's how I'm doing it now, but could someone suggest a better/more efficient way?
originalList = ['b', 'a', 'c', 'z', 'd']
listTemplate = ['a', 'b', 'c', 'd']
listFinal = []
for thing in listTemplate:
if thing in originalList:
listFinal.append(thing)
originalList.pop(originalList.index(thing))
for thing in originalList:
listFinal.append(thing)
originalList.pop(originalList.index(thing))
Try this:
originalList = ['b', 'a', 'c', 'z', 'd']
listTemplate = ['a', 'b', 'c', 'd']
order = { element:index for index, element in enumerate(listTemplate) }
sorted(originalList, key=lambda element: order.get(element, float('+inf')))
=> ['a', 'b', 'c', 'd', 'z']
This is how it works:
First, we build a dictionary indicating, for each element in listTemplate, its relative order with respect to the others. For example a is 0, b is 1 and so on
Then we sort originalList. If one of its elements is present in the order dictionary, then use its relative position for ordering. If it's not present, return a positive infinite value - this will guarantee that the elements not in listTemplate will end up at the end, with no further ordering among them.
The solution in the question, although correct, is not very pythonic. In particular, whenever you have to build a new list, try to use a list comprehension instead of explicit looping/appending. And it's not a good practice to "destroy" the input list (using pop() in this case).
You can create a dict using the listTemplate list, that way the expensive(O(N)) list.index operations can be reduced to O(1) lookups.
>>> lis1 = ['b', 'a', 'c', 'z', 'd']
>>> lis2 = ['a', 'b', 'c', 'd']
Use enumerate to create a dict with the items as keys(Considering that the items are hashable) and index as values.
>>> dic = { x:i for i,x in enumerate(lis2) }
Now dic looks like:
{'a': 0, 'c': 2, 'b': 1, 'd': 3}
Now for each item in lis1 we need to check it's index in dic, if the key is not found we return float('inf').
Function used as key:
def get_index(key):
return dic.get(key, float('inf'))
Now sort the list:
>>> lis1.sort(key=get_index)
>>> lis1
['a', 'b', 'c', 'd', 'z']
For the final step, you can just use:
listFinal += originalList
and it will add these items to the end.
There is no need to create a new dictionary at all:
>>> len_lis1=len(lis1)
>>> lis1.sort(key = lambda x: lis2.index(x) if x in lis2 else len_lis1)
>>> lis1
['a', 'b', 'c', 'd', 'z']
Here is a way that has better computational complexity:
# add all elements of originalList not found in listTemplate to the back of listTemplate
s = set(listTemplate)
listTemplate.extend(el for el in originalList if el not in s)
# now sort
rank = {el:index for index,el in enumerate(listTemplate)}
listFinal = sorted(originalList, key=rank.get)
I am trying to concatenate items in a list onto a string.
list = ['a', 'b', 'c', 'd']
string = ''
for i in list:
string.join(str(i))
You don't need a loop:
items = ['a', 'b', 'c', 'd']
result = "".join(items)
Note that it's a bad idea to use list as the name of a variable, because that prevents you from using list to mean the built-in type.
Is this what you are looking for?
>>> my_list = ['a', 'b', 'c', 'd']
>>> "".join(my_list)
'abcd'
You shouldn't use list as a variable name, since this will shadow the built-in class list.