Find all distinct permutations of a string where only certain indices are allowed to be permuted.
e.g string_perms('test_world', [2,3]) --> ['test_world', 'tets_world']
I have an answer but it looks very dirty. Is there a more elegant way to do it?
from itertools import permutations
def string_perms(s, indices):
final = []
target = [let for ind,let in enumerate(s) if ind in indices]
perms = list(set(permutations(target)))
temp = list(s)
for perm in perms:
for ind,let in enumerate(perm):
temp[indices[ind]] = let
final.append(''.join(temp))
return final
You can use an iterator with a list comprehension:
import itertools as it
def string_perms(s, indices):
for _i in it.permutations([s[j] for j in indices], len(indices)):
i = iter(_i)
yield ''.join(a if j not in indices else next(i) for j, a in enumerate(s))
print(list(string_perms('test_world', [2,3])))
Output:
['test_world', 'tets_world']
A variant, playing with numpy direct indexing.
import numpy as np
def string_perms(s, indices):
r = np.arange(len(s), dtype=int)
for p in list(permutations(indices)):
r[np.array(indices, dtype=int)] = p
yield ''.join(np.array(list(s))[r])
print(list(string_perms('test_world', [2,3])))
print(list(string_perms("azerty", [2,4,5])))
Output:
['test_world', 'tets_world']
['azerty', 'azeryt', 'aztrey', 'aztrye', 'azyret', 'azyrte']
Related
Hi How to add a number to each integer in the list A that generates new list B using python. also I want to generate n number of lists
Example:
a = [1,2,3] and n = 2
add k = 3 to each element in a that gives b = [4,5,6] and add k to list b that gives c = [7,8,9]
I achieved this using map function but I want to generate n number of lists.
def bw(n, k):
test_list = [1,2,3]
if n > 1:
res = list(map(lambda x :x+k, test_list))
return test_list, res
else:
return test_list
print bw(3, 2)
Output b = [4,5,6]
c = [7,8,9]
If you just want the final array:
def bw(n, k):
test_list = [1,2,3]
return [x+n*k for x in test_list]
print(bw(3, 2))
If you want a list of lists as well:
def bw(n, k):
test_list = [1,2,3]
res = []
for i in range(0,n):
test_list = [x+k for x in test_list]
res.append(test_list)
return test_list, res
print(bw(3, 2))
res = [x + k for x in test_list]
This is straight from GeeksforGeeks.
Here is a solution:
test_list = [1,2,3]
def bw(test_list, n, k):
output= []
temp = test_list
for i in range(n):
temp = [j + k for j in temp]
output.append(temp)
return output
print (bw(test_list, 2, 3))
I am a fresh python beginner and trying to extract the first element of the first n-th elements of a nested list. But it doesn't work so far.
Say:
list = [["Anna","w",15],["Peter","m",20],["Zani","m",10], ["Lily","w",19]]
Goal:
list_new = ['Anna','Peter','Zani'...(#until the n-th elements)]
If I want to first element of all the elements in the list, it should be:
for i in list:
for j in i:
print j[0]
But what if i only want to strip the first element of the n-th elements of the list, instead of all the elements.
For example for the first 2 elements:
I tried:
for i in list[0:2]:
for j in i:
print j[0]
but it didn't work.
What's more, if i want to give the value of n later by using
def sheet(list, n)
and the return statement, how could i do it?
Thank you very much!!
lst = [["Anna","w",15],["Peter","m",20],["Zani","m",10], ["Lily","w",19]]
n = 2
print(lst[n][0])
Output:
Zani
---Updated answer for the details added in the question---
l = [["Anna","w",15],["Peter","m",20],["Zani","m",10], ["Lily","w",19]]
n = 2
for i in range(n):
print(l[i][0])
Output:
Anna
Peter
You can use a list comprehension. Given an input list of lists L:
L_new = [i[0] for i in L[:n]]
Functionally, you can use operator.itemgetter. In addition, you can use itertools.islice to avoid creating an intermediary list:
from operator import itemgetter
from itertools import islice
L_new = list(map(itemgetter(0), islice(L, 0, n)))
Be careful, list is reserved for the built-in function list() in python, you should not use 'list' as variable name.
To get the first element of each nested list :
l = [["Anna","w",15],["Peter","m",20],["Zani","m",10], ["Lily","w",19]]
for e in l:
print(e[0])
Prints :
Anna
Peter
Zani
Lily
To do the same on the nth first elements :
def sheet(l, n):
return [e[0] for e in l[:n]]
sheet(l, 3)
Returns
['Anna', 'Peter', 'Zani']
EDIT
def sheet(l, n):
for e in l[:n]
return [e[0]]
This code only returns ['Anna'] because the return statement stops the function. The for loop is stopped at the first element.
def sheet(l, n):
return [e[0] for e in l[:n]]
is equivalent to :
def sheet(l, n):
result = [e[0] for e in l[:n]]
return result
which is equivalent to :
def sheet(l, n):
result = []
for e in l[:n]:
result.append(e[0])
return result
The for loop can ends before the return statement.
More informations here.
Just try this one which will be easier for you to understand:
n = int(input())
lst = [["Anna","w",15],["Peter","m",20],["Zani","m",10], ["Lily","w",19]]
lst_new = []
for item in lst[:n]:
name, *rest = item
lst_new.append(name)
I have a list of lists of strings, like this:
l = [['apple','banana','kiwi'],['chair','table','spoon']]
Given a string, I want its index in l. Experimenting with numpy, this is what I ended up with:
import numpy as np
l = [['apple','banana','kiwi'],['chair','table','spoon']]
def ind(s):
i = [i for i in range(len(l)) if np.argwhere(np.array(l[i]) == s)][0]
j = np.argwhere(np.array(l[i]) == s)[0][0]
return i, j
s = ['apple','banana','kiwi','chair','table','spoon']
for val in s:
try:
print val, ind(val)
except IndexError:
print 'oops'
This fails for apple and chair, getting an indexerror. Also, this just looks bad to me. Is there some better approch to doing this?
Returns a list of tuples containing (outer list index, inner list index), designed such that the item you're looking for can be in multiple inner lists:
l = [['apple','banana','kiwi'],['chair','table','spoon']]
def findItem(theList, item):
return [(ind, theList[ind].index(item)) for ind in xrange(len(theList)) if item in theList[ind]]
findItem(l, 'apple') # [(0, 0)]
findItem(l, 'spoon') # [(1, 2)]
If you want to use numpy, you don't need to roll your own:
import numpy as np
l = np.array([['apple','banana','kiwi'],['chair','table','spoon']])
s = ['apple','banana','kiwi','chair','table','spoon']
for a in s:
arg = np.argwhere(l==a)
print a, arg, tuple(arg[0]) if len(arg) else None
l = [['apple','banana','kiwi'],['chair','table','spoon']]
def search(lst, item):
for i in range(len(lst)):
part = lst[i]
for j in range(len(part)):
if part[j] == item: return (i, j)
return None
I'd create a dictionary to map the items to their indices:
>>> import numpy as np
>>> l = [['apple','banana','kiwi'],['chair','table','spoon']]
>>> a = np.array(l,dtype=object)
>>> a
array([[apple, banana, kiwi],
[chair, table, spoon]], dtype=object)
>>> d = {s:idx for (idx),s in np.ndenumerate(a)}
>>> d['apple']
(0, 0)
>>> d['chair']
(1, 0)
numpy + ndenumerate is nice for creating the index, but it's definitely not necessary. Of course, this is going to be most efficient if you can create the index once and then reuse it for subsequent searches.
One way is to make use of enumerate:
l = [['apple','banana','kiwi'],['chair','table','spoon']]
s = ['apple','banana','kiwi','chair','table','spoon']
for a in s:
for i, ll in enumerate(l):
for j, b in enumerate(ll):
if a == b:
print a, i, j
In your line that computes i, you already have the answer if you apply argwhere to the entire list, rather than each sublist. There is no need to search again for j.
def ind(s):
match = np.argwhere(np.array(l == s))
if match:
i, j = match[0]
else:
return -1, -1
This is will return the indeces of the first occurence of the string you're searching for.
Also, you might consider how this method is impacted as the complexity of the problem increases. This method will iterate over every element of your list, so the runtime cost increases as the list becomes bigger. So, if the number of test strings you're trying to find in the list also increases, you might want to think about using a dictionary to create a lookup table once, then subsequent searches for test strings are cheaper.
def make_lookup(search_list):
lookup_table = {}
for i, sublist in enumerate(list):
for j, word in enumerate(sublist):
lookup_table[word] = (i, j)
return lookup_table
lookup_table = make_lookup(l)
def ind(s):
if s in lookup_table:
return lookup_table[s]
else:
return -1, -1
To get index of list of list in python:
theList = [[1,2,3], [4,5,6], [7,8,9]]
for i in range(len(theList)):
if 5 in theList(i):
print("[{0}][{1}]".format(i, theList[i].index(5))) #[1][1]
This solution will find all occurrences of the string you're searching for:
l = [['apple','banana','kiwi','apple'],['chair','table','spoon']]
def findItem(theList, item):
return [(i, j) for i, line in enumerate(theList)
for j, char in enumerate(line) if char == item]
findItem(l, 'apple') # [(0, 0), (0, 3)]
findItem(l, 'spoon') # [(1, 2)]
I have one list, like so,
a = ['dog','cat','mouse']
I want to build a list that is a combination of the all the list elements and looks like,
ans = ['cat-dog', 'cat-mouse','dog-mouse']
This is what I came up with,
a = ['dog','cat','mouse']
ans = []
for l in (a):
t= [sorted([l,x]) for x in a if x != l]
ans.extend([x[0]+'-'+x[1] for x in t])
print list(set(sorted(ans)))
Is there a simpler and a more pythonic way!
How important is the ordering?
>>> a = ['dog','cat','mouse']
>>> from itertools import combinations
>>> ['-'.join(el) for el in combinations(a, 2)]
['dog-cat', 'dog-mouse', 'cat-mouse']
Or, to match your example:
>>> ['-'.join(el) for el in combinations(sorted(a), 2)]
['cat-dog', 'cat-mouse', 'dog-mouse']
The itertools module:
>>> import itertools
>>> map('-'.join, itertools.combinations(a, 2))
['dog-cat', 'dog-mouse', 'cat-mouse']
itertools is surely the way to go here. If you want to do it only with build-ins, use:
a = ['dog','cat','mouse']
ans = [x + '-' + y for x in a for y in a if x < y]
I'm doing this but it feels this can be achieved with much less code. It is Python after all. Starting with a list, I split that list into subsets based on a string prefix.
# Splitting a list into subsets
# expected outcome:
# [['sub_0_a', 'sub_0_b'], ['sub_1_a', 'sub_1_b']]
mylist = ['sub_0_a', 'sub_0_b', 'sub_1_a', 'sub_1_b']
def func(l, newlist=[], index=0):
newlist.append([i for i in l if i.startswith('sub_%s' % index)])
# create a new list without the items in newlist
l = [i for i in l if i not in newlist[index]]
if len(l):
index += 1
func(l, newlist, index)
func(mylist)
You could use itertools.groupby:
>>> import itertools
>>> mylist = ['sub_0_a', 'sub_0_b', 'sub_1_a', 'sub_1_b']
>>> for k,v in itertools.groupby(mylist,key=lambda x:x[:5]):
... print k, list(v)
...
sub_0 ['sub_0_a', 'sub_0_b']
sub_1 ['sub_1_a', 'sub_1_b']
or exactly as you specified it:
>>> [list(v) for k,v in itertools.groupby(mylist,key=lambda x:x[:5])]
[['sub_0_a', 'sub_0_b'], ['sub_1_a', 'sub_1_b']]
Of course, the common caveats apply (Make sure your list is sorted with the same key you're using to group), and you might need a slightly more complicated key function for real world data...
In [28]: mylist = ['sub_0_a', 'sub_0_b', 'sub_1_a', 'sub_1_b']
In [29]: lis=[]
In [30]: for x in mylist:
i=x.split("_")[1]
try:
lis[int(i)].append(x)
except:
lis.append([])
lis[-1].append(x)
....:
In [31]: lis
Out[31]: [['sub_0_a', 'sub_0_b'], ['sub_1_a', 'sub_1_b']]
Use itertools' groupby:
def get_field_sub(x): return x.split('_')[1]
mylist = sorted(mylist, key=get_field_sub)
[ (x, list(y)) for x, y in groupby(mylist, get_field_sub)]