Multiple loop in list comprehension - python

I have a problem set in hand, the description is something like:
We have 2 lists ie "nums1" and "nums2" and 2 integers m and n
nums1 = [1, 2, 3, 7, 8, 9]
m = 3
nums2 = [2, 5, 6]
n = 2
Here "m" denotes number of elements to be picked from "nums1" and "n" denotes the number of elements to be picked from "nums2".
There are other ways ofcourse, but I want to create a list with only "list comprehension" on the above conditions.
With a simple for loop I can achieve that with:
li = []
for i in range(m):
li.append(nums1[i])
for j in range(n):
li.append(nums2[j])
print(li)
I tried the following but the outcome result is not as expected:
[a for a in nums1 for b in nums2]
Expected output:
[1, 2, 2, 3, 5]
Also, does list comprehension supports multiple loop?

Given the following:
nums1 = [1, 2, 3, 7, 8, 9]
m = 3
nums2 = [2, 5, 6]
n = 2
Using strictly list comprehension, the following does what you asked for:
sorted([nums1[a] for a in range(m)] + [nums2[b] for b in range(n)])
Returns:
[1, 2, 2, 3, 5]
as per the conditions with "List comprehension" to be specific.
Although as others have said in the comment, a slice would have been more pythonic and easier to reason about. But since you asked for a list comprehension implementation, then this is as close to an answer as you'll get.

nums1 = [1, 2, 3, 7, 8, 9]
m = 3
nums2 = [2, 5, 6]
n = 2
ll = sorted([a for b in [nums1[:m], nums2[:n]] for a in b])
print(ll)
Output
[1, 2, 2, 3, 5]

nums1 = [1, 2, 3, 7, 8, 9]
m = 3
nums2 = [2, 5, 6]
n = 2
Create an empty list and store the returned values in this list if you need to access them later on in the program
nums3 = []
[nums3.append(nums1[i]) for i in range(m)]
[nums3.append(nums2[i]) for i in range(n)]
Sorts and prints the newly created list
print(sorted(nums3))

Related

Sublists from a python list such that first sublist contains first 2 elements of list, then first 3 elements and so on and Num as 3rd, 4th and so on

From a given list, I have to create sublists that follow a sequence as first 2 elements, then first 3 elements, then first 4 elements and so on from the given list and corresponding num as 3rd element, 4th element, 5th element, and so on. Used the below-given code, but it is not giving the 0 indexed list element i.e. 1. What's wrong?
list = [1, 3, 2, 10, 4, 8, 6]
list2 = []
Num = None
for i in range(2,len(list)):
print(f"i = {i}")
Num = list[i]
for j in range(0,i):
print(f"j = {j}")
list2.append(list[j])
print(f"\tlist2 = {list2}\tNum = {Num}")
print(f".........................................................")
Desired Output:
list2 = [1, 3] Num = 2
list2 = [1, 3, 2] Num = 10
list2 = [1, 3, 2, 10] Num = 4
list2 = [1, 3, 2, 10, 4] Num = 8
list2 = [1, 3, 2, 10, 4, 8] Num = 6
a = [1, 3, 2, 10, 4, 8, 6]
for i in range(2,len(a)):
print(f'list2 = {a[:i]} Num={a[i]}')
Output
list2 = [1, 3] Num=2
list2 = [1, 3, 2] Num=10
list2 = [1, 3, 2, 10] Num=4
list2 = [1, 3, 2, 10, 4] Num=8
list2 = [1, 3, 2, 10, 4, 8] Num=6
try changing
for i in range(2,len(list)):
condition to
for i in range(1,len(list)):
so the loop would start on the first element of the given list. This should solve the problem.

Is there a consistent expression for python list reverse selection?

The case is if I want to reverse select a python list to n like:
n = 3
l = [1,2,3,4,5,6]
s = l[5:n:-1] # s is [6, 5]
OK, it works, but how can I set n's value to select the whole list?
let's see this example, what I expect the first line is [5, 4, 3, 2, 1]
[40]: for i in range(-1, 5):
...: print(l[4:i:-1])
...:
[]
[5, 4, 3, 2]
[5, 4, 3]
[5, 4]
[5]
[]
if the upper bound n set to 0, the result will lost 0. but if n is -1, the result is empty because -1 means "the last one".
The only way I can do is:
if n < 0:
s = l[5::-1]
else:
s = l[5:n:-1]
a bit confusing.
To fully reverse the list by slicing:
l = [1,2,3,4,5,6]
print(l[::-1])
#[6, 5, 4, 3, 2, 1]
If you want to be able to partially or fully reverse the list based on the value of n, you can do it like this:
l = [1,2,3,4,5,6]
def custom_reverse(l,n):
return [l[i] for i in range(len(l)-1,n,-1)]
print(custom_reverse(l,3)) #[6, 5]
print(custom_reverse(l,-1)) #[6, 5, 4, 3, 2, 1]
Hopefully this is what you mean.
print(l[n+1::-1])

Swap and reverse elements in a python list

I have a list with elements as following:
L =[1, 2, 3, 4, 5]
I want to mirror and reorder as follows:
L =[1,5,2,4,3]
Numbers and size of elements in the list may vary and change!
Having some other examples,
K=[1, 2, 3]
Output may come out as:
K=[1, 3, 2]
And
D=[1,2,3,4]
Final results:
D = [1,4,2,3]
I have tried to do it with slice, it doesn't work for me.
You can do that by merging the list with its reverse:
lst = [1,2,3,4,5]
b = [c for a,b in zip(lst,reversed(lst)) for c in (a,b)][:len(lst)]
print(b) # [1, 5, 2, 4, 3]
Is this what you're looking for?
from random import shuffle
my_list = [1,2,3,4,5]
print (my_list)
shuffle (my_list)
print (my_list)
The following code gives you the expected output.
l = [1,2,3,4,5]
r = []
for i in range(len(l)):
if i % 2 == 0:
r.append(l[i // 2])
else:
r.append(l[-1 - i // 2])
print(r) # prints [1, 5, 2, 4, 3]

Does Python have a way of returning a list without the first n elements?

Say I have [1, 2, 3, 4, 5, 6]. And I want [3, 4, 5, 6].
Currently I'm doing:
l = [1, 2, 3, 4, 5, 6]
l[-(len(l) - n):]
I'm not familiar with Python style, but this seems pretty hack-y.
Yes, by slicing:
>>> n = 2
>>> l = [1, 2, 3, 4, 5, 6]
>>> l[n:]
[3, 4, 5, 6]
Read the tutorial here to have a further understanding on how to manipulate Python data structures that support slicing.
Get creative and put it in a function, as mentioned in the comments:
def slice_it(l, n):
return l[n:]
demo:
>>> slice_it(l, 2)
[3, 4, 5, 6]
And as a lambda, as shown in the comments:
sliced_list = lambda l, n: l[n:]
demo:
>>> sliced_list(l, 2)
[3, 4, 5, 6]
You can use positive int as slice lower bound:
l = [1, 2, 3, 4, 5, 6]
l[n:]
You can just l[n:], rather than using negative indexing with the full length of the list.
For example, if len(l) == 6 then:
l[2:] == l[-4:]
Keep in mind #idjaw has a much better answer,
You can also use list comprehensions, like so:
>>> l = [1, 2, 3, 4, 5, 6]
>>> n = 3
>>> l = [x + 1 for x in range(len(l)) if x >= n]
>>> l
[4, 5, 6]

remove duplicate element from a list, but only those who has odd number of duplicates

I am trying remove duplicate elements from the list, whose number of duplicates is odd.
For example for the following list: [1, 2, 3, 3, 3, 5, 8, 1, 8] I have 1 duplicated 2 times, 3 duplicated 3 times, and 8 duplicated 2 times. So 1 and 8 should be out and instead of 3 elements of 3 I need to leave only 1.
This is what I came up with:
def remove_odd_duplicates(arr):
h = {}
for i in arr:
if i in h:
h[i] += 1
else:
h[i] = 1
arr = []
for i in h:
if h[i] % 2:
arr.append(i)
return arr
It returns everything correctly: [2, 3, 5], but I do believe that this can be written in a nicer way. Any ideas?
You can use collections.Counter and list comprehension, like this
data = [1, 2, 3, 3, 3, 5, 8, 1, 8]
from collections import Counter
print [item for item, count in Counter(data).items() if count % 2]
# [2, 3, 5]
The Counter gives a dictionary, with every element in the input iterable as the keys and their corresponding counts as the values. So, we iterate over that dict and check if the count is odd and filter only those items out.
Note: The complexity of this solution is still O(N), just like your original program.
If order doesn't matter:
>>> a = [1, 2, 3, 3, 3, 5, 8, 1, 8]
>>> list(set([x for x in a if a.count(x)%2 == 1]))
[2, 3, 5]
The list comprehension [x for x in a if a.count(x)%2 == 1] returns only the elements which appear an odd number of times in the list. list(set(...)) is a common way of removing duplicate entries from a list.
you can possibly use scipy.stats.itemfreq:
>>> from scipy.stats import itemfreq
>>> xs = [1, 2, 3, 3, 3, 5, 8, 1, 8]
>>> ifreq = itemfreq(xs)
>>> ifreq
array([[1, 2],
[2, 1],
[3, 3],
[5, 1],
[8, 2]])
>>> i = ifreq[:, 1] % 2 != 0
>>> ifreq[i, 0]
array([2, 3, 5])

Categories