Extend list with another list in specific index? [duplicate] - python

This question already has an answer here:
list extend() to index, inserting list elements not only to the end
(1 answer)
Closed last month.
In python we can add lists to each other with the extend() method but it adds the second list at the end of the first list.
lst1 = [1, 4, 5]
lst2 = [2, 3]
lst1.extend(lst2)
Output:
[1, 4, 5, 2, 3]
How would I add the second list to be apart of the 1st element? Such that the result is this;
[1, 2, 3, 4, 5 ]
I've tried using lst1.insert(1, *lst2) and got an error;
TypeError: insert expected 2 arguments, got 3

For those who don't like reading comments:
lst1 = [1, 4, 5]
lst2 = [2, 3]
lst1[1:1] = lst2
print(lst1)
Output:
[1, 2, 3, 4, 5]

If your only goal is to get the list sorted correctly, then you use .extend() and .sort() afterwards.

You can solve your problem in two steps:
Insert the list into the other list
Flatten the result
Code:
from collections.abc import Iterable
# https://stackoverflow.com/questions/2158395/flatten-an-irregular-arbitrarily-nested-list-of-lists
def flatten(xs):
for x in xs:
if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
yield from flatten(x)
else:
yield x
xs = [1,4,5]
ys = [2,3]
xs.insert(1, ys)
print("intermediate result", xs)
xs = flatten(xs)
print(xs)

Related

How to make a flat list from nested lists? [duplicate]

This question already has answers here:
Flatten an irregular (arbitrarily nested) list of lists
(51 answers)
Closed 6 months ago.
Given a nested list of integers, implement an iterator to flatten it. Each
element is either an integer, or a list -- whose elements may also be integers
or other lists. For example, if the input is [[1,1],2,[1,1]], then the output
is [1, 1, 2, 1, 1]. If the input is [1,[4,[6]]], then the output is [1, 4, 6].
Would anyone be able to advise me as to where the code below went wrong?
I am just starting out with python.
def eb34(list1):
flat_list = []
for i in range(len(list1)):
if type(list[i]) == list:
flat_list += flatten(list1[i])
else:
flat_list.append(list1[i])
return flat_list
You can use recursion:
def flatten(arg):
if not isinstance(arg, list): # if not list
return [arg]
return [x for sub in arg for x in flatten(sub)] # recurse and collect
print(flatten([[1,1],2,[1,1]])) # [1, 1, 2, 1, 1]
print(flatten([1,[4,[6]]])) # [1, 4, 6]
Or to make a generator,
def flatten(arg):
if not isinstance(arg, list): # if not list
yield arg
else:
for sub in arg:
yield from flatten(sub)
print(*flatten([[1,1],2,[1,1]])) # 1 1 2 1 1
print(*flatten([1,[4,[6]]])) # 1 4 6
I don't know from where you are calling flatten() in your code. I am giving you a solution with the other information you have given.
def eb34(list1):
flat_list = []
for i in list1:
if isinstance(i, list):
for j in eb34(i):
flat_list.append(j)
else:
flat_list.append(i)
return flat_list
You can recursively flatten it:
def flatten_recursively(lst_in):
lst_out = []
for i in lst_in:
if type(i) == list:
for j in flatten_recursively(i):
lst_out.append(j)
else:
lst_out.append(i)
return lst_out
Also check out this answer, although you might have to adjust it to Python 3+: https://stackoverflow.com/a/10824420/18189622
The easiest way to make a flat list from nested lists is to use the itertools module. The itertools module has a function called chain that takes a list of lists and returns a single list.
>>> import itertools
>>> nested_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> flat_list = list(itertools.chain(*nested_lists))
>>> flat_list
[1, 2, 3, 4, 5, 6, 7, 8, 9]

Add two lists which return a list the addition of the adjacent element

I want to write a function add_list, which adds two lists adjacent elements.
E.g. l1 = [1, 2, 3], l2= [1,2,3] should give [2,4,6]. I am lost and not sure how to approach it using loops. Can someone help please?
You can iterate both the lists using zip and then use list comprehension on them
[x+y for x,y in zip(l1, l2)]
Sample run:
>>l1 = [1, 2, 3]
>>l2= [1,2,3]
>>[x+y for x,y in zip(l1, l2)]
[2, 4, 6]
Other possible solution is to iterate through the index (can be used in list comprehension as well)
result = []
for i in range(len(l1)):
result.append(l1[i] + l2[i])
Output:
>>result
[2, 4, 6]
The following code will add numbers in two given list provided that both have same number of elements
def add_list(a, b):
result = [] # empty list
# loop through all the elements of the list
for i in range(len(a)):
# insert addition into results
result.append(a[i] + b[i])
return result
l1 = [1, 2, 3]
l2 = [1, 2, 3]
print(add_list(l1, l2))

List comprehension output [duplicate]

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 3 years ago.
I am trying to understand list comprehension by passing a list a of functions to act on list as shown in the code below.
def fun1(x):
x.append(5)
print(" In Fun 1:")
print(x)
return x
def fun2(x):
x.append(6)
return x
def fun3(x):
x.append(7)
return x
int_list = [1, 2, 3, 4]
funs_family = (fun1, fun2, fun3)
new_list = [fun(int_list) for fun in funs_family ]
print(new_list)
I am expecting the result of the new_list to be
[1,2,3,4,5] [1,2,3,4,5,6] [1,2,3,4,5,6,7]
but the actual result is
[1,2,3,4,5,6,7] [1,2,3,4,5,6,7] [1,2,3,4,5,6,7]
Can anyone explain why the actual result is different from expected result?
Return a new list in your fun_family methods and you will not see the issue:
def fun1(x):
x.append(5)
print("In Fun 1:")
print(x)
return list(x)
def fun2(x):
x.append(6)
return list(x)
def fun3(x):
x.append(7)
return list(x)
int_list = [1, 2, 3, 4]
funs_family = (fun1, fun2, fun3)
new_list = [fun(int_list) for fun in funs_family]
print(new_list)
>> [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6, 7]]
Here's a similar example for you to look at
int_list = [1, 2, 3, 4]
funs_family = (fun1, fun2, fun3)
new_list = [int_list for fun in funs_family]
int_list.append(5)
print(new_list)
Note that new_list does not depend on the functions at all, in fact they're never called. But what's printed is [1, 2, 3, 4, 5] three times. This is because the three lists inside new_list all point to the same list in memory. So when you change the original, it changes all of them.
Because you are appending to the list, it is actually the same object. At the end you are printing the exact same list three times. Instead, maybe what you want to do is create a new list within the function and add the int to it.
x = [1, 2, 3, 4]
x_copy = [i for i in x]
x_copy.append(5)
Each of the functions returns x.
So
new_list = [fun(int_list) for fun in funs_family ] print(new_list)
… returns three copies of x, all of which are equal to [1,2,3,4,5,6,7] once the comprehension has finished.
What you want instead are copies of x, which you can get using [:]:
new_list = [fun(int_list)[:] for fun in funs_family ]

Appending variable that is modified in a for loop doesn't work as expected [duplicate]

This question already has answers here:
List on python appending always the same value [duplicate]
(5 answers)
Closed 4 years ago.
I have this code:
lst = []
given = [1, 2, 3, 4, 5]
result = []
for item in given:
lst.append(item)
print(lst)
result.append(lst)
print(result)
My expected result is [[1], [1, 2], [1, 2, 3], ...], but displayed result is [[1, 2, 3, 4, 5], ...] with 12345 repeated 5 times. What is wrong?
lst printed is as expected, which is [1] for the first loop, [1, 2] for the second loop, and so on.
Python doesn't create copy of lst every time when you append it to result, it just inserts reference. As a result you get list with N references to same list.
To create a copy of lst you can use lst.copy(). Also list slice operator works same lst[:].
Shortened version of your code:
given = [1, 2, 3, 4, 5]
result = [given[0 : i + 1] for i in range(len(given))]
print(result)
Result:
[[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]]
The problem is that you are appending the list as such which is equivalent to appending the reference object to the original list. Therefore, whenever the original list is modified, the changes are reflected in the places where the reference is created, in this case in result. As you keep iterating via the for loop, all your references appended in result keep getting updated with the latest value of lst. The final result is that at the end of the for loop, you have appended 5 references to the original list lst and all of them store the latest value of lst being [1,2,3,4,5].
There are several ways to avoid this. What you need is to copy only the values. One of them is to use lst[:]. other way is to use lst.copy()
for item in given:
lst.append(item)
print(lst)
result.append(lst[:])
print (result)
# [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]]
List is a mutable data type, there is only one copy in memory for a list unless you explicitly copy it to another variable. So
result.append(lst)
just appends a reference of the real copy and all the refercences point to the same copy.
In conclusion, you should learn about mutable/immutable data types and reference count in python.
Append lst.copy() gives the right output.
lst = []
given = [1,2,3,4,5]
result = []
for item in given:
lst.append(item)
print(lst)
result.append(lst.copy())
print(result)

Remove and return adjacent elements from a list [duplicate]

This question already has answers here:
Remove adjacent element in a list in python
(2 answers)
Closed 7 years ago.
I have a list like this: [1, 3, 4, 5, 1]
and I want to remove the first n elements, so for n = 3, I want to return that list, while removing it from the original list. So I'd have [1,3,4]
and my original list is now [5, 1].
What is the best way to do that in python?
In Python 2.7 this would look like the following. Simply extract a partial list and delete the unneeded part in the original version.
lst = [1, 3, 4, 5, 1]
new_lst = lst[:3]
del lst[:3]
print lst
print new_lst
If you want to mutate the original object, you can change it using [:]. For example:
>>> x = ['a','b','c','d','e']
>>> x[:], removed = x[3:], x[:3]
>>> x
['d', 'e']
>>> removed
['a', 'b', 'c']
This works because the terms on the right hand side, x[3:] and x[:3], are both evaluated before they're assigned to the targets on the left (x[:] and removed).
Something like this?
def pop_n(lst, n):
"""
Deletes the first *n* elements from *lst* and returns them.
"""
# validate inputs
# might want to use something other than isinstance()
if not isinstance(n, int) or n < 0:
raise ValueError("n must be a non-negative integer, not {}"
.format(n))
# store the elements to return
ret = lst[:n]
# remove the elements from the original list
del lst[:n]
return ret
EDIT: Here's a demonstration with your example case.
>>> x = [1, 3, 4, 5, 1]
>>> pop_n(x, 3)
[1, 3, 4]
>>> x
[5, 1]
>>> original = [1, 3, 4, 5, 1]
>>> removed, original[:3] = original[:3], ()
>>> removed, original
([1, 3, 4], [5, 1])

Categories