Merge two lists that are generated by a python code - python

I know we can merge two lists by using something like final_list= list1 + list2 but if the lists are generated by a python code and they don't have a variable associated with them like list1 and list2, how can we merge them? Say, my code does something like print output to give:
[1,2,3,4]
[2,0,5,6]
I'd like to merge them so I can get unique values using set(final_list). But how do I get the final_list?
PS- My code can return multiple lists. It is not restricted to two.

def somefunc(param):
#does something
return alist,blist
my_alist,my_blist = somefunc(myparam)
print my_alist, my_blist
#prints both lists.
When you return multiple values from a function they are returned in a tuple. You can easily unpack the tuple

You can either modify the function which is generating output, or the harder way being you manually convert it into a string and then into a set.
list = []
strings_of_list = output.split('\n')
for string in strings_of_list:
values = string[1:-1].split(',')
for val in values:
list+=[int(val)]
set(list)

Assign a variable to a function. Taking the lists the function generated, join them together in another variable. Just make sure that your function returns the generated list, and doesn't just print it out.
# my_list_generator returns two values.
>>> a, b = my_list_generator()
>>> a
[1, 2, 3, 4]
>>> b
[2, 0, 5, 6]
>>> final_list = a + b
>>> final_list
[1, 2, 3, 4, 2, 0, 5, 6]
Cross all that out! Now that I know the function can return multiple objects, let do this (with a little list comprehension):
lists = [i for i in my_list_generator()]
# lists might look like [[1, 2, 3, 4], [2, 0, 5, 6]]
# And now use a for loop to get each value
final_list = []
for sublist in lists:
final_list.extend(sublist)
# final_list will look like [1,2,3,4,2,0,5,6]
Also, if you don't want duplicates, just do one more thing:
real_final_list = [i for i in final_list if i not in real_final_list]

If I understand correctly:
You have a function (let's call it listGen() for now) which returns some number of lists. Now, you want to put these list together into one big list, final_list.
You could do the following:
# listGen defined earlier
final_list = []
for i in listGen():
final_list += i
unique_values = set(final_list) # or whatever you wanted to do with it
Since listGen returns a tuple, we can loop over its contents, those being the lists you want to append to each other.

Related

Creating lists while code is running and adding them to an List Parent

I am trying to create lists based on a value given by the user input and then I would like to add those lists created to a Parent list where they all can be accessed and used.
For example, I want the for loop to grab the number entered by the user, and based on that number it needs to create lists numbered from 1 to whatever they chose. At the end of each repetition I would like to add the created list to a parent list.
Here is what I have so far, I am struggling in adding them to the parent list I guess.
lists = int(input("How many lists do you want? "))
varname = 'iteration_number_'
parent_list = []
for i in range(lists):
iteration_number = i+1 #So it does not start from 0
iteration_names = varname + str(iteration_number) #merging the name and the number
x = parent_list.append(exec(f"{iteration_names} = []")) #creating lists with that name
try:
iteration_number_1.append("Cow") # appends Cow to the first list if existing
iteration_number_2.append("Moo") # appends Moo to the first list if existing
print(iteration_number_1)
print(iteration_number_2)
except NameError:
pass
print(parent_list)
parent_list[0].append("This is list iteration_number_1 but I'm not working")
The last part of the code doesn't work as planned. In my head when I print parent_list I should get [[iteration_number_1], [iteration_number_2]] and they can be accessed like this
parent_list[0].append("Hello") #appending to the iteration_number_1 list
Does anyone know a better idea? or how to make this idea work?
The programmers call them nested lists:
myNestedList = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
You can access the inner lists this way:
>>> myNestedList[0] # Get the first row
[1, 2, 3]
>>> myNestedList[0][2]
3
You can append elements to the inner lists this way:
>>> myNestedList[0].append(10)
>>> myNestedList
[[1, 2, 3, 10], [4, 5, 6], [7, 8, 9]]
I saw you are using strings as keys instead of integers, this way:
iteration_names = varname + str(iteration_number) #merging the name and the number
x = parent_list.append(exec(f"{iteration_names} = []")) #creating lists with that name
In your case it's a bad idea, but you could use dictionaries, this way:
myDict: dict = {
"iteration_name_1": <first-element-of-the-list>,
"iteration_name_2": <second-el...>
}
You can access the dictionary this way:
>>> myDict['iteration_name_1']
<first-element...>
If you tried this at the end of the program:
parent_list[0].append(iteration_name_1)
and it didn't work, I would suggest to create the lists by name this way (if you really need to call them with names like 'name_x'):
>>> locals()['iteration_name_1'] = []
>>> iteration_name_1
[]
It has nothing to do with the question, but...
for i in range(lists):
iteration_number = i+1 #So it does not start from 0
...you should know that a better practice is to do this:
for i in range(1, lists):
# i starts from 1
All and all...
The best practice would be doing this way:
for i in range(lists):
parent_list.append([])
try:
parent_list[0].append('Cow')
parent_list[1].append('Moo')
except IndexError: # There is a different exception for an element not found in parent_list
pass
You could try to a dictionary with the key as a string to the iteration number and the value as a list:
d = {}
d["iteration_number_1"] = []
...
d["iteration_number_1"].append("hello")

Leave parts of the instructions blank for python to complete

I'm new to Python so I don't know if this is possible, but my guess is yes. I want to iterate over a list and put items into new lists according to their value. For instance, if item_x == 4, I would want to put it in a list called list_for_4. The same is true for all other items in my list and numbers 0 to 10. So is it possible to generalize a statement in such a way that if item_x == *a certain value*, it will be appended to list_for_*a certain value*?
Thanks!
Maybe use list comprehension with if statement inside?
Like:
list_for_4 = [x for x in my_list if x==4]
And combine it with a dict.
With a simple iteration through the list:
lst_for_1 = []
lst_for_2 = []
lst_for_3 = []
d = {1: lst_for_1, 2: lst_for_2, 3: lst_for_3}
for x in lst:
d[x].append(x)
Or, if you want a condition that is more complicated than just the value of x, define a function:
def f(x):
if some condition...:
return lst_for_1
elif some other condition:
return lst_for_2
else:
return lst_for_3
Then replace d[x].append(x) by f(x).append(x).
If you don't want to do the iteration yourself, you could also use map:
list(map(lambda x: d[x].append(x),lst))
or
list(map(lambda x: f(x).append(x),lst))
The version with map will return an list of Nones that you don't care about. map(...) returns an iterator, and as long as you do not iterate through it (for example, to turn its result into a list), it will not perform the mapping. That's why you need the list(map(...)), it will create a dummy list but append the items of lst to the right lists on the way, which is what you want.
Don't know why you want to do it. But you can do it.
data = [1, 2, 3, 4, 1, 2, 3, 5]
for item in data:
name = f'list_for_{item}'
if name in globals():
globals()[name].append(item)
else:
globals()[name] = [item]
Instead of trying to generate a dynamic variables. A map using a dictionary structure might help you.
For example:
from collections import defaultdict
item_list = [1, 2, 3, 9, 2, 2, 3, 4, 4]
# Use a dictionary which elements are a list by default:
items_map = defaultdict(list)
for i in item_list:
items_map['list_for_{}'.format(i)].append(i)
print(items_map)
# Test the map for elements in the list:
if 'list_for_4' in items_map:
print(items_map['list_for_4'])
else:
print('`list_for_4` not found.')
Alternatively if you only require the number of times an item occurs in the list you could aggregate it using Counter:
from collections import Counter
item_list = [1, 2, 3, 9, 2, 2, 3, 4, 4]
result = Counter(item_list)
print(result)

Add part of the list to another list in Python [duplicate]

This question already has answers here:
How do I concatenate two lists in Python?
(31 answers)
Closed 2 months ago.
I am trying to understand if it makes sense to take the content of a list and append it to another list.
I have the first list created through a loop function, that will get specific lines out of a file and will save them in a list.
Then a second list is used to save these lines, and start a new cycle over another file.
My idea was to get the list once that the for cycle is done, dump it into the second list, then start a new cycle, dump the content of the first list again into the second but appending it, so the second list will be the sum of all the smaller list files created in my loop. The list has to be appended only if certain conditions met.
It looks like something similar to this:
# This is done for each log in my directory, i have a loop running
for logs in mydir:
for line in mylog:
#...if the conditions are met
list1.append(line)
for item in list1:
if "string" in item: #if somewhere in the list1 i have a match for a string
list2.append(list1) # append every line in list1 to list2
del list1 [:] # delete the content of the list1
break
else:
del list1 [:] # delete the list content and start all over
Does this makes sense or should I go for a different route?
I need something efficient that would not take up too many cycles, since the list of logs is long and each text file is pretty big; so I thought that the lists would fit the purpose.
You probably want
list2.extend(list1)
instead of
list2.append(list1)
Here's the difference:
>>> a = [1, 2, 3]
>>> b = [4, 5, 6]
>>> c = [7, 8, 9]
>>> b.append(a)
>>> b
[4, 5, 6, [1, 2, 3]]
>>> c.extend(a)
>>> c
[7, 8, 9, 1, 2, 3]
Since list.extend() accepts an arbitrary iterable, you can also replace
for line in mylog:
list1.append(line)
by
list1.extend(mylog)
To recap on the previous answers. If you have a list with [0,1,2] and another one with [3,4,5] and you want to merge them, so it becomes [0,1,2,3,4,5], you can either use chaining or extending and should know the differences to use it wisely for your needs.
Extending a list
Using the list classes extend method, you can do a copy of the elements from one list onto another. However this will cause extra memory usage, which should be fine in most cases, but might cause problems if you want to be memory efficient.
a = [0,1,2]
b = [3,4,5]
a.extend(b)
>>[0,1,2,3,4,5]
Chaining a list
Contrary you can use itertools.chain to wire many lists, which will return a so called iterator that can be used to iterate over the lists. This is more memory efficient as it is not copying elements over but just pointing to the next list.
import itertools
a = [0,1,2]
b = [3,4,5]
c = itertools.chain(a, b)
Make an iterator that returns elements from the first iterable until it is exhausted, then proceeds to the next iterable, until all of the iterables are exhausted. Used for treating consecutive sequences as a single sequence.
Take a look at itertools.chain for a fast way to treat many small lists as a single big list (or at least as a single big iterable) without copying the smaller lists:
>>> import itertools
>>> p = ['a', 'b', 'c']
>>> q = ['d', 'e', 'f']
>>> r = ['g', 'h', 'i']
>>> for x in itertools.chain(p, q, r):
print x.upper()
You can also combine two lists (say a,b) using the '+' operator.
For example,
a = [1,2,3,4]
b = [4,5,6,7]
c = a + b
Output:
>>> c
[1, 2, 3, 4, 4, 5, 6, 7]
That seems fairly reasonable for what you're trying to do.
A slightly shorter version which leans on Python to do more of the heavy lifting might be:
for logs in mydir:
for line in mylog:
#...if the conditions are met
list1.append(line)
if any(True for line in list1 if "string" in line):
list2.extend(list1)
del list1
....
The (True for line in list1 if "string" in line) iterates over list and emits True whenever a match is found. any() uses short-circuit evaluation to return True as soon as the first True element is found. list2.extend() appends the contents of list1 to the end.
You can simply concatnate two lists, e.g:
list1 = [0, 1]
list2 = [2, 3]
list3 = list1 + list2
print(list3)
>> [0, 1, 2, 3]
Using the map() and reduce() built-in functions
def file_to_list(file):
#stuff to parse file to a list
return list
files = [...list of files...]
L = map(file_to_list, files)
flat_L = reduce(lambda x,y:x+y, L)
Minimal "for looping" and elegant coding pattern :)
you can use __add__ Magic method:
a = [1,2,3]
b = [4,5,6]
c = a.__add__(b)
Output:
>>> c
[1,2,3,4,5,6]
If we have list like below:
list = [2,2,3,4]
two ways to copy it into another list.
1.
x = [list] # x =[] x.append(list) same
print("length is {}".format(len(x)))
for i in x:
print(i)
length is 1
[2, 2, 3, 4]
2.
x = [l for l in list]
print("length is {}".format(len(x)))
for i in x:
print(i)
length is 4
2
2
3
4

Remove matching items in a list

Sorry if this is a duplicate question, I searched and couldn't find anything to help.
I'm currently trying to compare two lists. If there are any matching items I will remove them all from one of the lists.
However the results I have are buggy. Here is a rough but accurate representation of the method I'm using:
>>> i = [1,2,3,4,5,6,7,8,9]
>>> a = i
>>> c = a
>>> for b in c:
if b in i:
a.remove(b)
>>> a
[2, 4, 6, 8]
>>> c
[2, 4, 6, 8]
So I realised that the main issue is that as I remove items it shortens the list, so Python then skips over the intermediate item (seriously annoying). As a result I made a third list to act as an intermediate that can be looped over.
What really baffles me is that this list seems to change also even when I haven't directly asked it to!
In python, when you write this:
i = [1,2,3,4,5,6,7,8,9]
You create an Object (in this case, a list) and you assign it to the name i. Your next line, a = i, tells the interpreter that the name a refers to the same Object. If you want them to be separate Object you need to copy the original list. You can do that via the slicing shorthand, i[:], or you can use a = list(i) to be more explicit.
The easiest way to do this is use a set to determine shared items in a and b:
for x in set(a).intersection(b):
a.remove(x)
Your statements a = i and c = a merely make new names that reference the same object. Then as you removed things from a, it's removed from b and i, since they are the same object. You'll want to make copies of the lists instead, like so
a = i[:]
c = a[:]
a = i Doesn't make a copy of a list, it just sets another variable, i to point at your list a. Try something like this:
>>> i = [1, 2, 3, 2, 5, 6]
>>> s = []
>>> for i in t:
if i not in s:
s.append(i)
>>> s
[1, 2, 3, 5, 6]
You can also use set which guarantees no duplicates, but doesn't preserve the order:
list(set(i))

Why does list comprehension not filter out duplicates?

I have a workaround to the following question. That workaround would be a for loop with a test for inclusion in the output like the following:
#!/usr/bin/env python
def rem_dup(dup_list):
reduced_list = []
for val in dup_list:
if val in reduced_list:
continue
else:
reduced_list.append(val)
return reduced_list
I am asking the following question, because I am curious to see if there is a list comprehension solution.
Given the following data:
reduced_vals = []
vals = [1, 2, 3, 3, 2, 2, 4, 5, 5, 0, 0]
Why does
reduced_vals = = [x for x in vals if x not in reduced_vals]
produce the same list?
>>> reduced_vals
[1, 2, 3, 3, 2, 2, 4, 5, 5, 0, 0]
I think it has something to do with checking the output (reduced_vals) as part of an assignment to a list. I am curious, though as to the exact reason.
Thank you.
The list comprehension creates a new list, while reduced_vals points to the empty list all the time during the evaluation of the list comprehension.
The semantics of assignments in Python are: Evaluate the right-hand side and bind the resulting object to the name on the left-hand side. An assignment to a bare name never mutates any object.
By the way, you should use set() or collections.OrderedDict.fromkeys() to remove duplicates in an efficient way (depending on whether you need to preserve order or not).
You are testing against an empty list.
The expression is evaluated in full first before assigning it as the new value of reduced_vals, which thus remains empty until the full list expression has been evaluated.
To put it differently, the expression [x for x in vals if x not in reduced_vals] is executed in isolation. It might help if you view your code in a slightly modified fashion:
temp_var = [x for x in vals if x not in reduced_vals]
reduced_vals = temp_var
del temp_var
The above is the moral equivalent of directly assigning the result of the list expression to reduced_vals, but I have more clearly separated assigning the result by using a second variable.
In this line: [x for x in vals if x not in reduced_vals] there's not a single value that is not in reduced_vals, as reduced_vals is the empty list []. In other words, nothing gets filtered and all the elements in vals get returned.
If you try this:
[x for x in vals if x in reduced_vals]
The result is the empty list [], as all the values are not in reduced_vals (which is empty). I believe you have a confusion with how the filtering part works in a list comprehension: you see, the filter only selects those values which make the condition True, but it won't prevent duplicate values.
Now, if what you need is to filter out duplicates, then a list comprehension is not the right tool for the job. For that, use a set - although it won't necessarily preserve the order of the original list, it'll guarantee that the elements are unique:
vals = [1, 2, 3, 3, 2, 2, 4, 5, 5, 0, 0]
list(set(vals))
> [0, 1, 2, 3, 4, 5]
Because the elements in the list comprehension are not assigned to reduced_vals until the entire list has been constructed. Use a for loop with .append() if you want to make this work.
Because reduced_vals is not changing during evaluation of the list comprehension.

Categories

Resources