Related
I'm solving a problem where I must find an unique integer in a list, which is easily solvable using list.count(x). However, I'm having trouble condensing the code into one line.
def find_uniq(arr):
return [x for x in arr if arr.count(x) == 1]
My code works fine, but it returns for example: [2] instead of 2, or [0.55] instead of 0.55.
Is there a way to return the integer instead of the list containing the integer, using list comprehension?
You have already the answers for list-comprehension -- which is a waste of resources.
Your approach, though, is valid since it makes use of everyday/beginner structures. In the same argument, I would like to suggest two things:
avoid the redundant calls to count();
avoid the creation of a list (since all you want is one element a time).
Suppose we have the following array arr:
> arr = [random.randint(0,9) for _ in range(10)]
> arr
[6, 7, 0, 9, 3, 3, 3, 9, 8, 8]
To the first point, you can create a set to reduce the number of counts:
> numbers_set = set(arr)
> numbers_set
{0, 3, 6, 7, 8, 9}
Then you can have a generator with the help of our friend filter:
> unique_numbers = filter(lambda x:arr.count(x)==1, numbers_set)
> print(next(unique_numbers))
0
> print(next(unique_numbers))
6
> print(next(unique_numbers))
7
> print(next(unique_numbers))
StopIteration:
Instead of a list comprehension which produces a list, create a generator from which you take the first element:
return next(x for x in arr if arr.count(x) == 1)
This raises a StopIteration is no element in the list fulfils the criteria; you can instead return a default value like None like so:
return next((x for x in arr if arr.count(x) == 1), None)
It's also questionable whether it's wise to iterate the array again and again with count; depending on its size, that can be very inefficient. It may be more efficient to build a counter first:
from collections import Counter
return next(v for v, c in Counter(arr).items() if c == 1)
If you are sure that You want to return only one integer from the passed list You can change the return to
def find_uniq(arr):
return [x for x in arr if arr.count(x) == 1][0]
But it will return only first element that is unique in the list. If You want to return more of them the list is better approach
Return using indexing.
def find_uniq(arr):
return [x for x in arr if arr.count(x) == 1][0]
I am trying to write a simple python code which would find a list k nearest elements to origin using a max heap. My main question is around the usage of the map in python, I tried to code it in this way, and I am getting a list of Nones as output whereas I was expecting max_heap to be populated with values pushed by heappush/heappushpop. Can someone point what's wrong here? Also, I am wondering if I really need to declare max_heap empty list? Is there a way in which I can write this entire logic in 1 statement? Thanks!
def find_closest_k_nums(nums, k):
max_heap = []
for num in nums:
if len(max_heap) == k + 1:
heapq.heappushpop(max_heap, -num)
else:
heapq.heappush(max_heap, -num), nums
return [-s for s in heapq.nlargest(k, max_heap)]
# >>> find_closest_k_nums([1, 5, 6, 3, 8, 9, 10], 4) => [1, 3, 5, 6]
# I tried to write the above function using map but I got an empty list.
def find_closest_k_nums_with_map(nums, k):
max_heap = []
map(lambda x: heapq.heappushpop(max_heap, -x)
if len(max_heap) == k + 1 else heapq.heappush(max_heap, -x), nums)
return [-s for s in heapq.nlargest(k, max_heap)]
# >>> find_closest_k_nums_with_map([1, 5, 6, 3, 8, 9, 10], 4) => []
map returns an iterable which calls the function on demand as you ask for elements from the iterable. More simply:
>>> def increment(x):
... print(f"Calling increment on {x}")
... return x + 1
...
>>> x = [1,2,3]
>>> y = map(increment, x)
Until you iterate over y, increment is never called. Only as you call next on y does increment get called.
>>> next(y)
Calling increment on 1
2
>>> next(y)
Calling increment on 2
3
In order for the elements of nums to be added to your heap in the your second function, you need to (somehow) iterate over the elements that map will yield. For example, pass the map object to list to force iteration:
def find_closest_k_nums_with_map(nums, k):
max_heap = []
list(map(lambda x: heapq.heappushpop(max_heap, -x)
if len(max_heap) == k + 1 else heapq.heappush(max_heap, -x), nums))
return [-s for s in heapq.nlargest(k, max_heap)]
But this is terrible style. You aren't actually interested in the return value of the function getting mapped over nums, only its side effect of updating max_heap. When that is the case, just use a for loop as in your first function.
Please help me with this.
For example, if I have a = [2, 5, 8, 4] and b = [1, 3, 6, 9].
how would I used "for" loop to pick an element in 'a' and its corresponding element in 'b' to use in other function? For instance, pick 2 in 'a' and pick 1 in 'b' then next pick 5 in 'a' and 3 in 'b'.
What you want is the zip() function:
Make an iterator that aggregates elements from each of the iterables.
You can use it like this:
a = [2, 5, 8, 4]
b = [1, 3, 6, 9]
def another_function(x, y):
print(x, y)
for item_a, item_b in zip(a, b):
another_function(item_a, item_b)
You get:
(2, 1)
(5, 3)
(8, 6)
(4, 9)
You can also use map() function:
Return an iterator that applies function to every item of iterable, yielding the results.
Your function should return a value:
def another_function(x, y):
return x, y
result = map(another_function, a, b)
for item in result:
print(item)
You get the same result.
The situation you are facing is called "Parallel Arrays". Wikipedia has a great explanation and example code.
If you know the lists are the same length, just use zip:
for a_elem, b_elem in zip(a, b):
# do stuff with the elements
If your lists might be different lengths, zip will give you a sequence the length of your shortest iterable. Use itertools.izip_longest if you need a sequence the length of your longest iterable.
Can't you just access one element after another using the same position in one for loop defining a function?
def access_A_and_B(a,b,number)
for i in range(len(a)): #itterate through a until you find your number
if(a[i] == number and len(b) > i): # if a at position i is your number
return b[i] #ask b what the corresponding value is and return it
return -1 #default value if number not in a
number: is the number you want to search
for x, y in zip(a, b):
some_func(x, y)
Im trying to write a function that takes a list and can print the lowest integer that is within that list. Now i'm trying to figure out what to do where this works with nested lists that if the lowest number is within one of those nested lists then overall it will print that number. My code is here:
def listMin():
list2 = [3,4,[2,99,8],7]
for i in range (len(list2)):
if type(list2[i]) == type([]):
y=min(i)
list2.append(y)
print "hello"
if len(list2)== 0:
return None
else:
x= min(list2)
print x
listMin()
while this seems like it should print the number 2 it doesnt and just gives me an error once it reaches the nested list saying:
TypeError: 'int' object is not iterable
ive tried multiple things but i'm having a hard time as to why this sort of thing isn't working.
Nesting One Deep
In your example, the list is nested only one deep. If this is the case in general, then try:
>>> list2 = [3,4,[2,99,8],7]
>>> min(x if isinstance(x, int) else min(x) for x in list2)
2
Nesting of Arbitrary Depth
If deeper nesting is allowed, define this recursive function:
>>> def rmin(lst): return min(x if isinstance(x, int) else rmin(x) for x in lst)
...
In operation:
>>> rmin(list2)
2
Or, with deeper nesting:
>>> list3 = [3,4,[[2,99],8],7]
>>> rmin(list3)
2
>>> list4 = [3, 4, [[2, [99, 1]], 8], 7]
>>> rmin(list4)
1
How it works
The function rmin consists of the single line:
return min(x if isinstance(x, int) else rmin(x) for x in lst)
As you can see, this is a list comprehension that looks at every value x of the list lst.
Let's divide the argument of min into two parts. The first is:
x if isinstance(x, int) else rmin(x)
This returns x if x is an integer. Otherwise, it calls rmin on x. In the latter case, rmin recursively looks at every value in x and returns the minimum.
The second part of the argument of min is:
for x in lst
This is just the usual for a list comprehension. It extracts each value in lst in turn and assigns it to x.
In general, you could flatten your list of lists and search for min in the flattened list. There are many recipes for flattening. Here is one that I took from here.
import collections
def flatten(iterable):
for el in iterable:
if isinstance(el, collections.Iterable) and not isinstance(el, str):
yield from flatten(el)
else:
yield el
list2 = [3,4,[2,99,8],7]
print(list(flatten(list2)))
# [3, 4, 2, 99, 8, 7]
print(min(flatten(list2)))
# 2
This will work on multiple nested list as well, e.g.:
list2 = [3,4,[2,99,8,[-1,-2]],7]
print(list(flatten(list2)))
# [3, 4, 2, 99, 8, -1, -2, 7]
print(min(flatten(list2)))
# -2
The problem is caused by the line
y=min(i)
where i is an integer but not a list. You probably want y = min(list2[i]).
Note that while you have appended this y back to the original list, the loop would not reach the newly added element, since i will only range up to the original length of the list.
With some simple Python idioms, your original idea can be expressed in a more readable way as follows:
def listMin():
lst = [3,4,[2,99,8],7]
for x in lst:
if type(x) == list:
lst.append(min(x))
print min(lst)
listMin()
When I needed to do something similar, I wrote following:
import copy
def nestedMin(list_):
target_list = copy.deepcopy(list_) # to keep original list unchanged
for index in range (len(target_list)):
if type (target_list[index]) is list:
target_list[index] = nestedMin(target_list[index])
return min(target_list)
I know that it is not very efficient, keeps doing deepcopy; but it's readable and it does the job :)
Example:
list1 = [2,3,[4, -5, [7, -20]]]
print nestedMin(list1) # prints -20
print list1 # prints [2, 3, [4, -5, [7, -20]]]
I want to shuffle the elements of a list without importing any module.
The type of shuffle is a riffle shuffle. It is where you want to divide the number of elements of the list into two and then interleave them.
If there are odd number of elements then the second half should contain the extra element.
eg:
list = [1,2,3,4,5,6,7]
Then the final list should look like
[1,4,2,5,3,6,7]
Just for fun, a recursive solution:
def interleave(lst1, lst2):
if not lst1:
return lst2
elif not lst2:
return lst1
return lst1[0:1] + interleave(lst2, lst1[1:])
Use it as follows in Python 2.x (In Python 3.x, use // instead of /):
lst = [1,2,3,4,5,6,7]
interleave(lst[:len(lst)/2], lst[len(lst)/2:])
=> [1, 4, 2, 5, 3, 6, 7]
The above will work fine with lists of any length, it doesn't matter if the length is even or odd.
listA = [1,2,3,4,5,6,7,8,9]
listLen = len(listA)/2
listB = listA[:listLen]
listC = listA[listLen:]
listD = []
num = 0
while num < listLen:
if len(listB) >= num:
listD.append(listB[num])
listD.append(listC[num])
num += 1
if len(listA)%2 != 0:
listD.append(listC[num])
print listD
After looking at another answer, I also am adding a recursive version, which is a revised version of the other guy's answer, but easier to call as you only have to call the function with a single argument (The list you are trying to have shuffled) and it does everything else:
def interleave(lst):
def interleaveHelper(lst1,lst2):
if not lst1:
return lst2
elif not lst2:
return lst1
return lst1[0:1] + interleaveHelper(lst2, lst1[1:])
return interleaveHelper(lst[:len(lst)/2], lst[len(lst)/2:])
When you go to call it, you can say interleave(list)
eg: list = [1,2,3,4,5,6,7]
then the final list should look like [1,4,2,5,3,6,7]
Here's a function that should do this reliably:
def riffle(deck):
'''
Shuffle a list like a deck of cards.
i.e. given a list, split with second set have the extra if len is odd
and then interleave, second deck's first item after first deck's first item
and so on. Thus:
riffle([1,2,3,4,5,6,7])
returns [1, 4, 2, 5, 3, 6, 7]
'''
cut = len(deck) // 2 # floor division
deck, second_deck = deck[:cut], deck[cut:]
for index, item in enumerate(second_deck):
insert_index = index*2 + 1
deck.insert(insert_index, item)
return deck
and to unit-test it...
import unittest
class RiffleTestCase(unittest.TestCase):
def test_riffle(self):
self.assertEqual(riffle(['a','b','c','d','e']), ['a','c','b','d','e'])
self.assertEqual(riffle([1,2,3,4,5,6,7]), [1,4,2,5,3,6,7])
unittest.main()
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
You could do this fairly easily with by utilizing the next feature of an iterator in Python.
First thing you'll want to do is split the elements into two parts.
Next, turn those two parts into iterators using Python's iter function. You could skip this step, but I find calling next(iterable) to be a lot cleaner than manually indexing a list.
Finally, you'll loop through the first half of your list, and for each element you add of that half, add the corresponding element of the latter (calling next gives the next item in the sequence).
For example:
elements = [1,2,3,4,5,6,7]
half_point = len(elements)/2
a = iter(elements[0:half_point])
b = iter(elements[half_point: ])
result = []
for i in range(half_point):
result.append(next(a))
result.append(next(b))
if len(elements) % 2 != 0:
result.append(next(b))
print result
>>> [1, 4, 2, 5, 3, 6, 7]
The last bit at the bottom checks to see if the list is odd. If it is, that it appends the final element onto the end of the list.
If you get creative, you could probably condense this down a good bit by zipping and then unpacking, but I'll leave that for when you explore itertools ;)
You can split the input list into two parts, then use zip and some list manipulation to interleave the items.
n = 9
l = range(1,n+1)
a = l[:n/2]
b = l[n/2:]
c = zip(a,b)
d = list()
for p in c :
d.extend(list(p))
if n%2==1:
d.append(b[n/2])
print(d)
def riffle(deck):
new_deck = []
deck_1 = deck[:len(deck)//2]
deck_2 = deck[len(deck)//2::]
for i in range(len(deck)//2):
new_deck.append(deck_1[i])
new_deck.append(deck_2[i])
if len(deck) % 2 == 1:
new_deck.append(deck[-1])
return new_deck
deck = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
print(riffle(deck))
You may find the expression i%2, which evaluates to 0 on even numbers and 1 on odd numbers, to alternatively access the beginning and middle of the deck.
def riffle(deck: List[int]) -> List[int]:
result = []
mid = len(deck) // 2
for i in range(len(deck)):
result.append(deck[i // 2 + (i % 2) * mid])
return result
Or you can utilize an if expression for the odd and even numbers respectively:
def riffle(deck: List[int]) -> List[int]:
result = []
mid = len(deck) // 2
for i in range(len(deck)):
if not i % 2:
result.append(deck[i // 2])
else:
result.append(deck[i // 2 + mid])
return result
>>> ll = list(range(1,8))
>>> mid = len(ll)/2 # for Python3, use '//' operator
>>> it1 = iter(ll[:mid])
>>> it2 = iter(ll[mid:])
>>> riff = sum(zip(it1,it2), ()) + tuple(it2)
>>> riff
(1, 4, 2, 5, 3, 6, 7)
If this is homework, be prepared to explain how sum and zip working here, what the second parameter to sum is for, why tuple(it2) is being added to the end, and how this solution has an inherent inefficiency.
If deck is a list, write a function that does list comprehension to perform the shuffling:
def riffle_shuffle(deck):
return [deck[i//2 + (i%2)*(len(deck)//2)] for i in range(len(deck))]