I'm stuck on a question where I have to add 2 lists together while factoring in the length. For example, if list1 = [1,2] and list2 = [3,4,5] the answer would be [1+3,2+4,5] or [4,6,5].
What I have so far is:
def addsum(list1,list2):
new_list = []
if len(list1) > len(list2):
new_list = list1[0:]+list2[0:]
I'm not really sure how to appraoch this question since I'm new to lists. Would appreciate the help!
You should use zip_longest from itertools with a fillvalue of 0 in a list comprehension:
r = [sum(i) for i in zip_longest(list1, list2, fillvalue=0)]
zip_longest pairs the elements in the input lists (list1 and list2 here). If one list is smaller, pairs the remainding elements of the larger list with the value supplied as the fillvalue (which we assign to 0 here).
Now, r equals:
print(r) # [4, 6, 5]
Similarly, you could utilize map instead of the list-comp:
# Python 3.x
r = list(map(sum, zip_longest(list1, list2, fillvalue=0)))
# Python 2.7
r = map(sum, zip_longest(list1, list2, fillvalue=0))
and get the same result for r.
Poor man's approach:
def addsum(list1,list2):
if len(list1) >= len(list2):
for i in range(len(list2)):
list1[i]=list1[i]+list2[i]
return list1
else:
for i in range(len(list1)):
list2[i]=list1[i]+list2[i]
return list2
I would use the zip_longest solution too, but building in your code this is what I would do
def addsum(list1, list2):
if len(list1) < len(list2):
list1, list2 = list2, list1
result=list(list1)
for i,x in enumerate(list2):
result[i] += x
return result
first make sure that the first list is the longest, and if that is not the case exchange them, then make a copy of longest list and finally add the elements of the shorter list position-wise to the copy and return it
>>> addsum([1,2],[3,4,5])
[4, 6, 5]
>>>
Although zip_longest is more neat, another possibility is to use a trial/error approach (if you are tired of "ifs"), as shown here:
def addsum(list1, list2):
res = []
i = 0
while i < len(list1) or i < len(list2):
try:
res.append(list1[i]+list2[i])
except IndexError:
try: res.append(list1[i])
except IndexError: res.append(list2[i])
i += 1
return res
Documentation on zip_longest:
Make an iterator that aggregates elements from each of the iterables. If the iterables are of uneven length, missing values are filled-in with fillvalue. Iteration continues until the longest iterable is exhausted.
Here's the code:
from itertools import zip_longest
[x + y for x, y in zip_longest([1,2], [3,4,5], fillvalue=0)]
Output:
[4, 6, 5]
Related
I am looking for a way to iterate through the product of two lists that can sometimes be empty.
I was going to use itertools.product for that, so it would look like this:
import itertools
list1 = [1, 2]
list2 = ['a', 'b']
for i, j in itertools.product(list1, list2):
print(i, j)
We would get:
1 a
1 b
2 a
2 b
And that's what I expect. But when one of the lists is empty, the loop won't print anything:
list1 = [1, 2]
list2 = []
for i, j in itertools.product(list1, list2):
print(i, j)
Whereas I would like it to behave as if there was just one list. So, using itertools, do the equivalent of:
for i in itertools.product(list1):
print(i)
which would have returned:
(1,)
(2,)
I could put this into a long if statement, but I am looking for a simple tweak that would easily scale if the number of lists increased. Thanks for your help.
Put them in one variable and filter them to use only the non-empty ones:
import itertools
lists = [1, 2], []
for i in itertools.product(*filter(bool, lists)):
print(i)
Or if having them in separate variables is truly what you want:
import itertools
list1 = [1, 2]
list2 = []
for i in itertools.product(*filter(bool, (list1, list2))):
print(i)
Output of both:
(1,)
(2,)
One way of doing it would be checking if any of the lists is empty and putting in some value, but this is not the most elegant solution. For example:
import itertools
list1 = [1, 2]
list2 = []
if len(list2) == 0:
list2.append("")
for i, j in itertools.product(list1, list2):
print(i, j)
Here's what I want the layout to look. I want it to be a function so I can use it in the cmd prompt. The lengths of each list have to be the same, if not it should return none
def add_elements(list1, list2):
if len(list1)==len(list2):
for i in list1:
else:
None
I dont know if the "for i in list1:" is what I should use, if so what comes after?
Use the list index in your for loop
list1 = [1,2,3,4,5]
list2 = [5,4,3,2,1]
def add_elements(list1, list2):
if len(list1) != len(list2): return None
lst = []
if len(list1)==len(list2):
for i in range(len(list1)):
lst.append(list1[i] + list2[i])
return lst
print(add_elements(list1, list2))
Output
[6, 6, 6, 6, 6]
If the zip function is permitted, this is faster:
list1 = [1,2,3,4,5]
list2 = [5,4,3,2,1]
lst = [a+b for a,b in zip(list1, list2)]
print(lst)
Output
[6, 6, 6, 6, 6]
If I understand you correctly I think this is what your looking for:
def add_elements(list1, list2):
if len(list1) == len(list2):
results = []
for i in range (len(list1)):
results.append(list1[i] + list2[i])
return results
else:
return None
l1 = [1,2,3,4]
l2 = [5,6,7,8]
l3 = [1,2,3,4,5,6]
print(add_elements(l1, l2))
print(add_elements(l1, l3)
If the lists are the same length, the for loop will iterate over the length of the lists adding the elements. The last few lines (outside the function definition) will prove that the function works. The first print statement will give you the resulting list. The second print statement will show 'None' because l1 and l3 are different lengths.
I hope this is helpful.
I get:
if(lst[i]%2!=0):
IndexError: list index out of range
from this code:
lst=[1,2,3,4,5,6]
for i in range(len(lst)):
if(lst[i]%2!=0):
lst.remove(lst[i])
print(lst)
I am trying to print only the even numbers in a list and I do not see a problem with my code
why am I getting this error ?
You should not remove from a list while iterating it. Use, for instance, a list comprehension and slice assignment to achieve the same modification:
lst = [1,2,3,4,5,6]
lst[:] = [x for x in lst if x % 2 == 0]
# or simply (if you don't need to mutate the original list)
# lst = [x for x in lst if x % 2 == 0]
print(lst)
# [2, 4, 6]
This has also better time complexity (linear) whereas the repeated remove approach is quadratic.
Instead of removing the item from the original list, you can also split the original list into 2 new lists, evens and odds
lst=[1,2,3,4,5,6]
evens = []
odds = []
for i in lst):
if(i % 2 != 0):
odds.append(i)
else:
evens.append(i)
print(evens)
I am given a problem where I have a function that takes two integer lists and returns a single integer list (new list) with the two integer lists zipped together.
For example:
list1 = [1,2,3]
list2 = [4,5,6]
Should give [1, 4, 2, 5, 3, 6] not [1, 2, 3, 4, 5, 6]
Another case is if one list is longer than another, e.g:
list1 = [1,2]
list2 = [4,5,6,9]
Once the shorter list runs out of items, the longer list should add its remaining elements. E.g: [1, 4, 2, 5, 6, 9]
I have tried using conditional statements to check which list is longer and use a for loop to append to a new list that should be returned. I tried using for loops that loop for the duration of the shorter list, and once the for loop is over, it adds the remaining elements from longer list to the new list. Also if both lists are empty I have to return an empty new list.
The code:
def main():
list1 = [1,2]
list2 = [4,5,6,9]
print(zip_lists(list1, list2))
def zip_lists(list1, list2):
new_list = []
if len(list1) > len(list2):
last_num = list1[len(list1):]
for num in range(0, len(list2)):
new_list.append(list1[num])
new_list.append(list2[num])
new_list.append(last_num)
return new_list
elif len(list2) > len(list1):
last_num = list2[len(list2):]
for num in range(0, len(list1)):
new_list.append(list1[num])
new_list.append(list2[num])
new_list.append(last_num)
return new_list
elif len(list1) and len(list2) == 0:
return new_list
main()
However, I have a problem where I cannot add the remaining elements from the longer list and instead returns a partially zipped list with empty square brackets.
The test case:
list1 = [1,2]
list2 = [4,5,6,9]
Should be [1, 4, 2, 5, 6, 9] but I'm getting [1, 4, 2, 5, []].
Is my code showing the right way of thinking about this problem?
def zip_lists(list1, list2):
n1=len(list1)
n2=len(list2)
k = []
n = min(n1, n2)
for i in range(n):
k.append(list1[i])
k.append(list2[i])
if n1==n2:
return k
if n1>n2:
return k+list1[n:]
else:
return k+list2[n:]
Test:
list1 = [1,2]
list2 = [4,5,6,9]
zip_lists(list1, list2)
Output: [1, 4, 2, 5, 6, 9]
You can use zip_longest to do that like:
Code:
from itertools import zip_longest
def merge(l1, l2):
for i in zip_longest(l1, l2):
for j in i:
if j is not None:
yield j
Test Code:
list1 = [1, 2, 3]
list2 = [4, 5, 6]
ans1 = [1, 4, 2, 5, 3, 6]
list3 = [1, 2]
list4 = [4, 5, 6, 9]
ans2 = [1, 4, 2, 5, 6, 9]
assert list(merge(list1, list2)) == ans1
assert list(merge(list3, list4)) == ans2
A general version of this (i.e., for any number of source iterables, of possibly different lengths) is shown in the Python documentation for the itertools standard library, named roundrobin in the "recipes" section. Copied here, with the original credit:
def roundrobin(*iterables):
"roundrobin('ABC', 'D', 'EF') --> A D E B F C"
# Recipe credited to George Sakkis
num_active = len(iterables)
nexts = cycle(iter(it).__next__ for it in iterables)
while num_active:
try:
for next in nexts:
yield next()
except StopIteration:
# Remove the iterator we just exhausted from the cycle.
num_active -= 1
nexts = cycle(islice(nexts, num_active))
Here, cycle and islice are the functions provided by itertools (from itertools import cycle, islice); the rest is built-in. Note that this is a generator, not a normal function; you will need to iterate over it yourself (or directly create e.g. a list from it, e.g. merged = list(roundrobin(list1, list2))).
As far as debugging your attempt at the code, let's consider the case where list1 is longer (the case where list2 is longer has parallel problems; and the case where they're equal is working fine, yes?):
last_num = list1[len(list1):] # problem 1
for num in range(0, len(list2)):
new_list.append(list1[num])
new_list.append(list2[num])
new_list.append(last_num) # problem 2
Problem 1: you want to extract the "excess" elements from list1, which you determine as all the ones past a certain point. This is just a typo or not thinking about it clearly; you want to use the length of list2 for the number of elements to slice off; of course, using the length of list1 to remove elements from list1 removes everything.
Problem 2: you have a list whose elements you want to concatenate to the end of another list. .append treats its parameter as a single new list element, even if it's a list; like the Zen of Python says, special cases aren't special enough to break the rules (keep in mind that sometimes you might want to do this, after all). The method you're looking for, instead, is .extend.
import numpy as np
l=len(a) if len(a)<len(b) else len(b)
a=np.array(list1[:l])
b=np.array(list2[:l])
ab=np.vstack((a, b)).T.flatten()
res=list(ab)+list1[l:]+list2[l:]
This is what I have so far:
list1= raw_input('Enter first list of integers, with comma after each number: ')
list2 = raw_input('Enter second list of integers, with comma after each number: ')
list1 = list1.split(',') #makes lists
list2 = list2.split(',')
list1 = (int(x) for x in list1) #turns them into integers
list2 = (int(x) for x in list2)
secondlist = []
for x in list2:
if x ==
while x in list2 == list1[x]+1 or list1[x]-1:
I'm having trouble figuring out how to have it check every item in list1 with one item in list2.
Well it's not SUPER simple, but you could do it in two list comprehensions.
import itertools
# lst1 and 2 are already ints
valid_numbers = set(itertools.chain.from_iterable([(num-1, num, num+1) for num in lst1]))
result = [num for num in lst2 if num in valid_numbers]
This will only loop through lst1 twice and lst2 once, rather than looping through lst1 N times (once per element in lst2). Because of this, it should be much quicker as lst2 grows.
Loop through the second list, then loop through the first, checking if the absolute value of the two numbers is 0 or 1 and add to the result list if true.
Example:
l1 = [1, 2, 3, 4]
l2 = [4, 5, 7, 0, 75]
matches = []
for i2 in l2:
for i1 in l1:
if abs(i1 - i2) <= 1:
matches.append(i2)
break
matches is [4, 5, 0]
If you're interested in a one-liner:
[y for y in l2 if any(abs(x - y) <= 1 for x in l1)]
Implementing this with your code would look like
list1 = raw_input('Enter first list of integers, with comma after each number: ').split(',')
list2 = raw_input('Enter second list of integers, with comma after each number: ').split(',')
list1 = map(int, list1)
list2 = map(int, list2)
secondlist = [y for y in l2 if any(abs(x - y) <= 1 for x in l1)]
# Let's suppose you already have the lists
list1 = [1,2,3,4,5]
list2 = [1,2,3,4,5, 2,3,4, 2]
# Count occurences
occurences = {}
for item in list2:
if item in occurences:
occurences[item]+=1
else:
occurences[item]=1
ones = set([])
for item in list1:
if (occurences.get(item+1,0)>0) or (occurences.get(item-1,0)>0):
ones.add(item)
print ones
More or less the same as the absolute value based one-liner above, but a little more understandable to me at a glance.
>>> lst1 = [2, 3, 4, 5, 6]
>>> lst2 = [4, 5, 6, 7, 8]
>>> [n for n in lst2 if n in lst1 or n+1 in lst1 or n-1 in lst1]
[4, 5, 6, 7]
What do you mean by "within one unit in the first list"? The following is my understanding of this sentence.
def within_one(xlist, x):
within = False
for i in xlist:
if x >= i-1 and x =< i+1:
within = True
break
return within
print([j for j in list2 if within_one(list1, j)])
This one should be O(2n*(1+log(n))): sorting the input lists takes O(n log(n)) per list and then both lists are traversed exactly once, O(n).
mk_nm = lambda nm: "Enter {0}> ".format( nm )
readlist = lambda nm: sorted(map(int, raw_input(mk_nm(nm)).strip().split(',')))
# read the input lists and transform them into sorted lists of ints
list1 = readlist("list1")
list2 = readlist("list2")
# The accumulator holds the output list and
# the current list1
def reductor(acc, l2item):
(output, l1) = acc
# process elements from l1 until we find one
# that is > current l2 item-1
for i in xrange(len(l1)):
if abs(l1[i] - l2item)<=1:
output.append(l2item)
if l1[i]>=l2item-1:
break
# remove elements from l1 that we processed
return (output, l1[i:])
found = reduce(reductor, list2, ([], list1))[0]
print "Found: ",found
Trying it:
Enter list1> 1,2,3,4
Enter list2> 4,5,7,0,70
Found: [0, 4, 5]
editing original answer...
A double list comprehension would work for this. As an algorithm it is O(n^2).
list1 = [10, 20, 30, 40]
list2 = [8, 21, 32, 39]
print [x for x in list2 for y in list1 if abs(x-y) <= 1]
If you find that the lists you are comparing are very large, or if you set up list1 a single time and you repeatedly search it with list2 or other lists, you may consider switching to a dictionary, also known as a hash table.
l1 = [x+1 for x in list1] #Just building the lists
l2 = [x-1 for x in list1] #
list1.extend(l1)
list1.extend(l2) #list1 now has x, x-1, and x+1 for each x
d = dict(zip(list1, list1))
print [x for x in list2 if x in d]
The dictionary will be O(n) for building the dictionary in the first place and then have average O(1) searching after that. Something to consider.