Related
How do you remove similar items in a list in Python but only for a given item. Example,
l = list('need')
If 'e' is the given item then
l = list('nd')
The set() function will not do the trick since it will remove all duplicates.
count() and remove() is not efficient.
use filter
assuming you write function that decide on the items that you want to keep in the list.
for your example
def pred(x):
return x!="e"
l=list("need")
l=list(filter(pred,l))
Assuming given = 'e' and l= list('need').
for i in range(l.count(given)):
l.remove(given)
If you just want to replace 'e' from the list of words in a list, you can use regex re.sub(). If you also want a count of how many occurrences of e were removed from each word, then you can use re.subn(). The first one will provide you strings in a list. The second will provide you a tuple (string, n) where n is the number of occurrences.
import re
lst = list(('need','feed','seed','deed','made','weed','said'))
j = [re.sub('e','',i) for i in lst]
k = [re.subn('e','',i) for i in lst]
The output for j and k are :
j = ['nd', 'fd', 'sd', 'dd', 'mad', 'wd', 'said']
k = [('nd', 2), ('fd', 2), ('sd', 2), ('dd', 2), ('mad', 1), ('wd', 2), ('said', 0)]
If you want to count the total changes made, just iterate thru k and sum it. There are other simpler ways too. You can simply use regEx
re.subn('e','',''.join(lst))[1]
This will give you total number of items replaced in the list.
List comprehension Method. Not sure if the size/complexity is less than that of count and remove.
def scrub(l, given):
return [i for i in l if i not in given]
Filter method, again i'm not sure
def filter_by(l, given):
return list(filter(lambda x: x not in given, l))
Bruteforce with recursion but there are a lot of potential downfalls. Still an option. Again I don't know the size/comp
def bruteforce(l, given):
try:
l.remove(given[0])
return bruteforce(l, given)
except ValueError:
return bruteforce(l, given[1:])
except IndexError:
return l
return l
For those of you curious as to the actual time associated with the above methods, i've taken the liberty to test them below!
Below is the method I've chosen to use.
def timer(func, name):
print("-------{}-------".format(name))
try:
start = datetime.datetime.now()
x = func()
end = datetime.datetime.now()
print((end-start).microseconds)
except Exception, e:
print("Failed: {}".format(e))
print("\r")
The dataset we are testing against. Where l is our original list and q is the items we want to remove, and r is our expected result.
l = list("need"*50000)
q = list("ne")
r = list("d"*50000)
For posterity I've added the count / remove method the OP was against. (For good reason!)
def count_remove(l, given):
for i in given:
for x in range(l.count(i)):
l.remove(i)
return l
All that's left to do is test!
timer(lambda: scrub(l, q), "List Comp")
assert(scrub(l,q) == r)
timer(lambda: filter_by(l, q), "Filter")
assert(filter_by(l,q) == r)
timer(lambda : count_remove(l, q), "Count/Remove")
assert(count_remove(l,q) == r)
timer(lambda: bruteforce(l, q), "Bruteforce")
assert(bruteforce(l,q) == r)
And our results
-------List Comp-------
10000
-------Filter-------
28000
-------Count/Remove-------
199000
-------Bruteforce-------
Failed: maximum recursion depth exceeded
Process finished with exit code 0
The Recursion method failed with a larger dataset, but we expected this. I tested on smaller datasets, and Recursion is marginally slower. I thought it would be faster.
I am trying to build an algorithm which will output a list of all permutations of an inputted string and I am getting very lost, especially when it comes to heap algorithm. I tried to copy the code listed on the Wikipedia page to no avail. I want a solution in base Python.
# Desired output
heaps_func('art')
['rta', 'tra', 'tar', 'rat', 'art', 'atr']
# Current code
def heaps_func(a):
lst=[a]
l=len(a)
if len(a)==1:
return lst
else:
for x in range(len(a)-1):
if x<(l-1):
if l%2==0:
k=list(a)
p=k[i]
k[i]=k[l-1]
k[l-1]=p
k=''.join(k)
lst.append(k)
else:
k=list(a)
p=k[0]
k[0]=k[l-1]
k[l-1]=p
k=''.join(k)
lst.append(k)
return lst
You can do it by using recursion. Here I am goiing to add the python code for you.
def heaps_func(a,size):
if size ==1:
a = ''.join(a)
print(a)
return
for i in range(size):
heaps_func(a,size-1)
if size%2==1:
a[0],a[size-1]=a[size-1],a[0]
else:
a[i], a[size - 1] = a[size - 1], a[i]
heaps_func(list('art'),3)
If the given string contains duplicate characters, this program will also print duplicate element. For example, in string "arr", 'r' contains two times. And output of this program will be :
arr rar rar arr rra rra
To get rid of this, we can use a list and before printing we will search on that list whether this element exist in the list or not. If not exist then we will print it and store it on the list.
Programs:
def heaps_func(a,size,listofwords):
if size ==1:
a = ''.join(a)
#print(a)
if listofwords.count(a)==0:
print(a)
listofwords.append(a)
return
for i in range(size):
heaps_func(a,size-1,listofwords)
if size%2==1:
a[0],a[size-1]=a[size-1],a[0]
else:
a[i], a[size - 1] = a[size - 1], a[i]
listofwords=[]
heaps_func(list('arr'),len('arr'),listofwords)
for details please read the following link . But there it is described in C/C++.
https://www.geeksforgeeks.org/heaps-algorithm-for-generating-permutations/
I have an Phone number here lets say : 98888888xx the last two XX are the numbers which I want to generate a sequence of like 988888811 , 9888888812, 988888813 and so on.
I am trying to learn python programming so can someone help me how would I go on writing a script for the same
You could use a list comprehension and range():
['98888888' + str(number).zfill(2) for number in range(100)]
['9888888800',
'9888888801',
'9888888802',
...
'9888888897',
'9888888898',
'9888888899']
A robust solution is to use recursion to handle many possible occurrences of "x":
import re
s = '98888888xx'
_len = len(re.sub('\d+', '', s))
def combos(d, current = []):
if len(current) == _len:
yield current
else:
for i in d[0]:
yield from combos(d[1:], current+[i])
_c = combos([range(1, 10)]*_len)
new_result = [(lambda d:re.sub('x', lambda _:str(next(d)), s))(iter(i)) for i in _c]
Output:
['9888888811', '9888888812', '9888888813', '9888888814', '9888888815', '9888888816', '9888888817', '9888888818', '9888888819', '9888888821', '9888888822', '9888888823', '9888888824', '9888888825', '9888888826', '9888888827', '9888888828', '9888888829', '9888888831', '9888888832', '9888888833', '9888888834', '9888888835', '9888888836', '9888888837', '9888888838', '9888888839', '9888888841', '9888888842', '9888888843', '9888888844', '9888888845', '9888888846', '9888888847', '9888888848', '9888888849', '9888888851', '9888888852', '9888888853', '9888888854', '9888888855', '9888888856', '9888888857', '9888888858', '9888888859', '9888888861', '9888888862', '9888888863', '9888888864', '9888888865', '9888888866', '9888888867', '9888888868', '9888888869', '9888888871', '9888888872', '9888888873', '9888888874', '9888888875', '9888888876', '9888888877', '9888888878', '9888888879', '9888888881', '9888888882', '9888888883', '9888888884', '9888888885', '9888888886', '9888888887', '9888888888', '9888888889', '9888888891', '9888888892', '9888888893', '9888888894', '9888888895', '9888888896', '9888888897', '9888888898', '9888888899']
Note that a simple solution in the form of a nested list comprehension presents itself when there are only two 'x':
d = [s.replace('x', '{}').format(a, b) for a in range(1, 10) for b in range(1, 10)]
However, multiple nested loops is not a clean approach to solving the problem when the input string contains three or more 'x's. Instead, recursion works best:
s = '98888888xxxxx'
_len = len(re.sub('\d+', '', s))
_c = combos([range(1, 10)]*_len)
new_result = [(lambda d:re.sub('x', lambda _:str(next(d)), s))(iter(i)) for i in _c]
Output (first twenty strings):
['9888888811111', '9888888811112', '9888888811113', '9888888811114', '9888888811115', '9888888811116', '9888888811117', '9888888811118', '9888888811119', '9888888811121', '9888888811122', '9888888811123', '9888888811124', '9888888811125', '9888888811126', '9888888811127', '9888888811128', '9888888811129', '9888888811131', '9888888811132']
After completing an assignment to create pascal's triangle using an iterative function, I have attempted to recreate it using a recursive function. I have gotten to the point where I can get it to produce the individual row corresponding to the number passed in as an argument. But several attempts to have it produce the entire triangle up to and including that row have failed. I even tried writing a separate function which iterates over the range of the input number and calls the recursive function with the iterated digit while appending the individual lines to list before returning that list. The desired output should be a list of lists where each internal list contains one row of the triangle. Like so:
[[1], [1, 1], [1, 2, 1]...]
Instead it returns a jumbled mess of a nested list completely filled with 1's.
Here is the recursive function in question, without the second function to append the rows (I really wanted 1 all inclusive function anyway):
def triangle(n):
if n == 0:
return []
elif n == 1:
return [1]
else:
new_row = [1]
last_row = triangle(n-1)
for i in range(len(last_row)-1):
new_row.append(last_row[i] + last_row[i+1])
new_row += [1]
return new_row
To be clear, I have already completed the assigned task, this is just to provide a deeper understanding of recursion...
Iterative solution:
def triangle(n):
result = []
for row in range(n):
newrow = [1]
for col in range(1, row+1):
newcell = newrow[col-1] * float(row+1-col)/col
newrow.append(int(newcell))
result.append(newrow)
return result
You just need to pass a list of lists through the recursion, and pick off the last element of the list (i.e. the last row of the triangle) to build your new row. Like so:
def triangle(n):
if n == 0:
return []
elif n == 1:
return [[1]]
else:
new_row = [1]
result = triangle(n-1)
last_row = result[-1]
for i in range(len(last_row)-1):
new_row.append(last_row[i] + last_row[i+1])
new_row += [1]
result.append(new_row)
return result
An alternative to happydave's solution, using tail recursion:
def triangle(n, lol=None):
if lol is None: lol = [[1]]
if n == 1:
return lol
else:
prev_row = lol[-1]
new_row = [1] + [sum(i) for i in zip(prev_row, prev_row[1:])] + [1]
return triangle(n - 1, lol + [new_row])
I think its shod be helpful, this code draw triangle and do it recursively:
def traingle(n):
if n == 1:
print(1)
return [1]
else:
answer = [1]
print_able = '1 '
previos = traingle(n-1)
for index in range(len(previos)-1):
eleman = previos[index]+previos[index+1]
answer.append(eleman)
print_able += str(eleman)+' '
answer.append(1)
print_able += '1'
print(print_able)
return answer
end = int(input())
traingle(end)
Yes, as Karl Knechtel also showed, recursive Pascal Triangle can go this way :
P=lambda h:(lambda x:x+[[x+y for x,y in zip(x[-1]+[0],[0]+x[-1])]])(P(h-1))if h>1 else[[1]]
print(P(10))
Fromg Google's Python Class:
E. Given two lists sorted in increasing order, create and return a merged
list of all the elements in sorted order. You may modify the passed in lists.
Ideally, the solution should work in "linear" time, making a single
pass of both lists.
Here's my solution:
def linear_merge(list1, list2):
merged_list = []
i = 0
j = 0
while True:
if i == len(list1):
return merged_list + list2[j:]
if j == len(list2):
return merged_list + list1[i:]
if list1[i] <= list2[j]:
merged_list.append(list1[i])
i += 1
else:
merged_list.append(list2[j])
j += 1
First of all, is it okay to use an infinite loop here? Should I break out of the loop using the break keyword when I'm done merging the list, or are the returns okay here?
I've seen similar questions asked here, and all the solutions look quite similar to mine, i.e. very C-like. Is there no more python-like solution? Or is this because of the nature of the algorithm?
This question covers this in more detail than you probably need. ;) The chosen answer matches your requirement. If I needed to do this myself, I would do it in the way that dbr described in his or her answer (add the lists together, sort the new list) as it is very simple.
EDIT:
I'm adding an implementation below. I actually saw this in another answer here which seems to have been deleted. I'm just hoping it wasn't deleted because it had an error which I'm not catching. ;)
def mergeSortedLists(a, b):
l = []
while a and b:
if a[0] < b[0]:
l.append(a.pop(0))
else:
l.append(b.pop(0))
return l + a + b
Here's a generator approach. You've probably noticed that a whole lot of these "generate lists" can be done well as generator functions. They're very useful: they don't require you to generate the whole list before using data from it, to keep the whole list in memory, and you can use them to directly generate many data types, not just lists.
This works if passed any iterator, not just lists.
This approach also passes one of the more useful tests: it behaves well when passed an infinite or near-infinite iterator, eg. linear_merge(xrange(10**9), xrange(10**9)).
The redundancy in the two cases could probably be reduced, which would be useful if you wanted to support merging more than two lists, but for clarity I didn't do that here.
def linear_merge(list1, list2):
"""
>>> a = [1, 3, 5, 7]
>>> b = [2, 4, 6, 8]
>>> [i for i in linear_merge(a, b)]
[1, 2, 3, 4, 5, 6, 7, 8]
>>> [i for i in linear_merge(b, a)]
[1, 2, 3, 4, 5, 6, 7, 8]
>>> a = [1, 2, 2, 3]
>>> b = [2, 2, 4, 4]
>>> [i for i in linear_merge(a, b)]
[1, 2, 2, 2, 2, 3, 4, 4]
"""
list1 = iter(list1)
list2 = iter(list2)
value1 = next(list1)
value2 = next(list2)
# We'll normally exit this loop from a next() call raising StopIteration, which is
# how a generator function exits anyway.
while True:
if value1 <= value2:
# Yield the lower value.
yield value1
try:
# Grab the next value from list1.
value1 = next(list1)
except StopIteration:
# list1 is empty. Yield the last value we received from list2, then
# yield the rest of list2.
yield value2
while True:
yield next(list2)
else:
yield value2
try:
value2 = next(list2)
except StopIteration:
# list2 is empty.
yield value1
while True:
yield next(list1)
Why stop at two lists?
Here's my generator based implementation to merge any number of sorted iterators in linear time.
I'm not sure why something like this isn't in itertools...
def merge(*sortedlists):
# Create a list of tuples containing each iterator and its first value
iterlist = [[i,i.next()] for i in [iter(j) for j in sortedlists]]
# Perform an initial sort of each iterator's first value
iterlist.sort(key=lambda x: x[1])
# Helper function to move the larger first item to its proper position
def reorder(iterlist, i):
if i == len(iterlist) or iterlist[0][1] < iterlist[i][1]:
iterlist.insert(i-1,iterlist.pop(0))
else:
reorder(iterlist,i+1)
while True:
if len(iterlist):
# Reorder the list if the 1st element has grown larger than the 2nd
if len(iterlist) > 1 and iterlist[0][1] > iterlist[1][1]:
reorder(iterlist, 1)
yield iterlist[0][1]
# try to pull the next value from the current iterator
try:
iterlist[0][1] = iterlist[0][0].next()
except StopIteration:
del iterlist[0]
else:
break
Here's an example:
x = [1,10,20,33,99]
y = [3,11,20,99,1001]
z = [3,5,7,70,1002]
[i for i in merge(x,y,z)]
hi i just did this exercise and i was wondering why not use,
def linear_merge(list1, list2):
return sorted(list1 + list2)
pythons sorted function is linear isn't it?
Here's my implementation from a previous question:
def merge(*args):
import copy
def merge_lists(left, right):
result = []
while (len(left) and len(right)):
which_list = (left if left[0] <= right[0] else right)
result.append(which_list.pop(0))
return result + left + right
lists = [arg for arg in args]
while len(lists) > 1:
left, right = copy.copy(lists.pop(0)), copy.copy(lists.pop(0))
result = merge_lists(left, right)
lists.append(result)
return lists.pop(0)
Another generator:
def merge(xs, ys):
xs = iter(xs)
ys = iter(ys)
try:
y = next(ys)
except StopIteration:
for x in xs:
yield x
raise StopIteration
while True:
for x in xs:
if x > y:
yield y
break
yield x
else:
yield y
for y in ys:
yield y
break
xs, ys, y = ys, xs, x
I agree with other answers that extending and sorting is the most straightforward way, but if you must merge, this will be a little faster because it does not make two calls to len every iteration nor does it do a bounds check. The Python pattern, if you could call it that, is to avoid testing for a rare case and catch the exception instead.
def linear_merge(list1, list2):
merged_list = []
i = 0
j = 0
try:
while True:
if list1[i] <= list2[j]:
merged_list.append(list1[i])
i += 1
else:
merged_list.append(list2[j])
j += 1
except IndexError:
if i == len(list1):
merged_list.extend(list2[j:])
if j == len(list2):
merged_list.extend(list1[i:])
return merged_list
edit
Optimized per John Machin's comment. Moved try outside of while True and extended merged_list upon exception.
According to a note here:
# Note: the solution above is kind of cute, but unforunately list.pop(0)
# is not constant time with the standard python list implementation, so
# the above is not strictly linear time.
# An alternate approach uses pop(-1) to remove the endmost elements
# from each list, building a solution list which is backwards.
# Then use reversed() to put the result back in the correct order. That
# solution works in linear time, but is more ugly.
and this link http://www.ics.uci.edu/~pattis/ICS-33/lectures/complexitypython.txt
append is O(1), reverse is O(n) but then it also says that pop is O(n) so which is which? Anyway I have modified the accepted answer to use pop(-1):
def linear_merge(list1, list2):
# +++your code here+++
ret = []
while list1 and list2:
if list1[-1] > list2[-1]:
ret.append(list1.pop(-1))
else:
ret.append(list2.pop(-1))
ret.reverse()
return list1 + list2 + ret
This solution runs in linear time and without editing l1 and l2:
def merge(l1, l2):
m, m2 = len(l1), len(l2)
newList = []
l, r = 0, 0
while l < m and r < m2:
if l1[l] < l2[r]:
newList.append(l1[l])
l += 1
else:
newList.append(l2[r])
r += 1
return newList + l1[l:] + l2[r:]