I need help in some basic python scrips, well I want to order a prayer in words from longer to shorter length and without repeating, until then everything is fine, what happens is that I do not know how to do to order words of the same length alphabetically.
Since you're asking for a case where the 2 iterators will not be of the same order, you'll have to do it differently. You can consult this question Sort by multiple keys using different orderings. But since it doesn't contain what you really wanted, I'll answer it here:
from itertools import groupby
s = ['ddd', 'bb', 'ab', 'aa', 'cc', 'dab']
l = [sorted(list(g)) for b, g in groupby(s, key=lambda x: len(x))]
l = [e for x in l for e in x]
>>> l
['dab', 'ddd', 'aa', 'ab', 'bb', 'cc']
This sort by negative order for length but positive order for words. Explanation: the first list comprehension turns the list of string into a list of list that contain sorted lists (by alphanumeric) of strings of same length. The second list comprehension unwraps the list of list into one list.
Related
Is there a way for me to 'align' a list of strings to the right? I'm performing a counting sort here and I want sort my characters from the right.
For example, given a list of strings
eg. list = ['abc', 'a','qwerty', 'cd']
The length of the longest string in the list is 6 (qwerty),
list = ['abc', 'a','qwerty', 'cd']
biggest = max(list, key=len)
max = biggest - 1
list2= []
for col in range(-max, 0):
for i in list:
list2.append(i[abs(col)])
As my other strings are not the same length as qwerty, there will be an error, how do I 'align' all my strings to the right? so when I try to sort from the last alphabet, 'a' would be aligned with 'y' from 'qwerty' too.
a
cd
abc
qwerty
And I would like to accomplish this without padding
You can sort your whole list by length and use the format mini language for output:
data = ['abc', 'a','qwerty', 'cd']
s = sorted(data, key=len) # sorted copy of your list
maxlen = len(s[-1]) # longest is last element in sorted list
for l in s:
print(f"{l:>{maxlen}}") # not padded, just printed out right aligned
Output:
a
cd
abc
qwerty
As far as I understand the question, this should be the solution:
list_1 = ['aaaz', 'abc', 'a', 'qwerty', 'cd', "xxxxxxxxca"]
def my_sort(data):
inverted = sorted(data, key=lambda x: x[::-1])
return inverted
max_len = max([len(s) for s in list_1])
list_2 = my_sort(list_1)
print(list_2)
>>> ['a', 'xxxxxxxxca', 'abc', 'cd', 'qwerty', 'aaaz']
I understand that the strings should be sorted alphabetically but from right to left.
list_1 = ['abc', 'a','qwerty', 'cd']
biggest = max(list, key=len)
biggest=len(biggest)
list_2=[]
//with padding
for i in list_1:
list_2.append(' '*(biggest-len(i))+i)
//without padding
for i in list_1:
list_2.append(f"{i:>{biggest}}")
I'd go with this approach
I would like to find all subsets of a sorted string, disregarding order and which characters are next to each other. I think the best way for this to be explained is though an example. The results should also be from longest to shortest.
These are the results for bell.
bell
bel
bll
ell
be
bl
el
ll
b
e
l
I have thought of ways to do this, but none for any length of input.
Thank you!
There are generally two ways to approach such things: generate "everything" and weed out duplicates later, or create custom algorithms to avoid generating duplicates to begin with. The former is almost always easier, so that's what I'll show here:
def gensubsets(s):
import itertools
for n in reversed(range(1, len(s)+1)):
seen = set()
for x in itertools.combinations(s, n):
if x not in seen:
seen.add(x)
yield "".join(x)
for x in gensubsets("bell"):
print(x)
That prints precisely what you said you wanted, and how it does so should be more-than-less obvious.
Here is one way using itertools.combinations.
If the order for strings of same length is important, see #TimPeters' answer.
from itertools import combinations
mystr = 'bell'
res = sorted({''.join(sorted(x, key=lambda j: mystr.index(j)))
for i in range(1, len(mystr)+1) for x in combinations(mystr, i)},
key=lambda k: -len(k))
# ['bell', 'ell', 'bel', 'bll', 'be', 'll', 'bl', 'el', 'l', 'e', 'b']
Explanation
Find all combinations of length in range(1, len(mystr)+1).
Sort by original string via key argument of sorted. This step may be omitted if not required.
Use set of ''.join on elements for unique strings.
Outer sorted call to go from largest to smallest.
You can try in one line:
import itertools
data='bell'
print(set(["".join(i) for t in range(len(data)) for i in itertools.combinations(data,r=t) if "".join(i)!='']))
output:
{'bel', 'bll', 'ell', 'el', 'be', 'bl', 'e', 'b', 'l', 'll'}
How can I format this function so that it works recursively? I want to go multiple levels deeper if possible, not just until 5.
permutations is a list with different permutations, and those individual permutation can also have permutations, etc. I want to rank them based on some calculations I do in get_permutations and return the new order of permutations. A good way to look at it is probably a large list of lists of lists of lists of lists. First I want to change the order of the first level, than one step deeper etc. But eventually I return the string based on those permutations and not the permutation itself (if that matters), with res1...res5 being the strings. I'm not smart enough to get it to work recursively, even though I know it should be possible...Any ideas?
permutations, res1 = get_permutations(str, 1)
for p2 in permutations:
permutations_2, res2 = get_permutations(p2,2)
for p3 in permutations_2:
permutations_3, res3 = get_permutations(p3,3)
for p4 in permutations_3:
permutations_4, res4 = get_permutations(p4, 4)
for p5 in permutations_4:
permutations_5, res5 = get_permutations(p5,5)
res4 += res5
res3 += res4
res2 += res3
res1 += res2
return res1
EDIT: this returns a single (best) permutation. That is what the result is for. So not a list of possible permutations, as mentioned in the answers. E.g. if we have a lists of lists of lists, if first sorts the list based on all subinformation, then sorts the multiple lists of lists based on the previous sorts and all subinformation and then sorts the lists of lists of lists based on the previous 2 sorts.
A recursive generator function that yields permutations in the expected order with regard to the original string:
def get_permutations(a):
if len(a) <= 1:
yield a
else:
for i in xrange(len(a)):
for p in get_permutations(a[:i]+a[i+1:]):
yield ''.join([a[i]])+p
>>> a = '123'
>>> list(get_permutations(a))
['123', '132', '213', '231', '312', '321']
The recursive principle here:
Base case: strings of lengthes (0, 1) have only one permutation: themselves.
Recursion: for each letter in the string, remove it and prepend it to each permutation of the string's remainder.
An example below, This method works by nesting for loops in a recursive manner repeat-times. We then accumulate the result of the sub-solutions, appending to a result list:
result = []
def permutations(alphabet, repeat, total = ''):
if repeat >= 1:
for i in alphabet:
# Add the subsolutions.
permutations(alphabet, repeat - 1, total + i)
else:
result.append(total)
return result
Sample Outputs:
permutations('ab', 3) ->
$ ['aaa', 'aab', 'aba', 'abb', 'baa', 'bab', 'bba', 'bbb']
permutations('ab', 3) ->
$ ['aaa', 'aab', 'aac', 'aba', 'abb', 'abc', 'aca', 'acb', 'acc', 'baa',
'bab', 'bac', 'bba', 'bbb', 'bbc', 'bca', 'bcb', 'bcc', 'caa', 'cab',
'cac', 'cba', 'cbb', 'cbc', 'cca', 'ccb', 'ccc']
permutations('ab', 1) ->
$ ['a', 'b']
Source: a previous answer of mine.
I have a list of names alphabetically, like:
list = ['ABC', 'ACE', 'BED', 'BRT', 'CCD', ..]
How can I get element from each starting letter? Do I have to iterate the list one time? or Does python has some function to do it? New to python, this may be a really naive problem.
Suppose I want to get the second element from names that starts from 'A', this case I get 'ACE'.
If you're going to do multiple searches, you should take the one-time hit of iterating through everything and build a dictionary (or, to make it simpler, collections.defaultdict):
from collections import defaultdict
d = defaultdict(list)
words = ['ABC', 'ACE', 'BED', 'BRT', 'CCD', ...]
for word in words:
d[word[0]].append(word)
(Note that you shouldn't name your own variable list, as it shadows the built-in.)
Now you can easily query for the second word starting with "A":
d["A"][1] == "ACE"
or the first two words for each letter:
first_two = {c: w[:2] for c, w in d.items()}
Using generator expression and itertools.islice:
>>> import itertools
>>> names = ['ABC', 'ACE', 'BED', 'BRT', 'CCD']
>>> next(itertools.islice((name for name in names if name.startswith('A')), 1, 2), 'no-such-name')
'ACE'
>>> names = ['ABC', 'BBD', 'BED', 'BRT', 'CCD']
>>> next(itertools.islice((name for name in names if name.startswith('A')), 1, 2), 'no-such-name')
'no-such-name'
Simply group all the elements by their first char
from itertools import groupby
from operator import itemgetter
example = ['ABC', 'ACE', 'BED', 'BRT', 'CCD']
d = {g:list(values) for g, values in groupby(example, itemgetter(0))}
Now to get a value starting with a:
print d.get('A', [])
This is most usefull when you have a static list and will have multiple queries since as you may see, getting the 3rd item starting with 'A' is done in O(1)
You might want to use list comprehensions
mylist = ['ABC', 'ACE', 'BED', 'BRT', 'CCD']
elements_starting_with_A = [i for i in mylist if i[0] == 'A']
>>> ['ABC', 'ACE']
second = elements_starting_with_A[1]
>>> 'ACE'
In addition to list comprehension as others have mentioned, lists also have a sort() method.
mylist = ['AA', 'BB', 'AB', 'CA', 'AC']
newlist = [i for i in mylist if i[0] == 'A']
newlist.sort()
newlist
>>> ['AA', 'AB', 'AC']
The simple solution is to iterate over the whole list in O(n) :
(name for name in names if name.startswith('A'))
However you could sort the names and search in O(log(n)) for the item which is supposed to be on the index or after (using lexicographic comparison). The module bisect will help you to find the bounds :
from bisect import bisect_left
names = ['ABC', 'ACE', 'BED', 'BRT', 'CCD']
names.sort()
lower = bisect_left(names, 'B')
upper = bisect_left(names, chr(1+ord('B')))
print [names[i] for i in range(lower, upper)]
# ['BED', 'BRT']
I know how to generate combinations of a set and that's a builtin in Python (what I use), anyway. But how to generate combinations with replacements?
Suppose I have a set with, say, two identical elements - for example, AABCDE.
Combinations of 3 items could be:
"AAB"
"ABC"
"CDE"
However, the program would count ABC twice - once when using the first A, and the second one using the second A.
What is a good way to generate such combinations without duplicates?
Thanks.
convert it to set, that's the easiest way to get rid of duplicates.
>>> import itertools
>>> ["".join(x) for x in (itertools.combinations(set("AABCDE"),3))]
['ACB', 'ACE', 'ACD', 'ABE', 'ABD', 'AED', 'CBE', 'CBD', 'CED', 'BED']
>>>
From your other comments, I think I misunderstood what you are asking.
>>> import itertools
>>> set("".join(x) for x in (itertools.combinations("AABCDE",3)))
set(['AAE', 'AAD', 'ABC', 'ABD', 'ABE', 'AAC', 'AAB', 'BCD', 'BCE', 'ACD', 'CDE', 'ACE', 'ADE', 'BDE'])
def stepper_w_w(l,stop):#stepper_with_while
"""l is a list of any size usually you would input [1,1,1,1...],
stop is the highest number you want to stop at so if you put in stop=5
the sequence would stop at [5,5,5,5...]
This stepper shows the first number that equals the last.
This generates combinations with replacement. """
numb1=1
while numb1<stop:
#print(numb1)
l[0]=numb1
NeL=0
while l[len(l)-1]<=numb1:
if l[NeL]==l[len(l)-1]:
l[NeL]+=1
l[(NeL+1):]=[1]*((len(l))-(NeL+1))
print(l)
"""iter_2s=NeL+1
while iter_2s<=(len(l)-1): #this is different from above
l[iter_2s]=2
iter_2s+=1
print(l)"""
NeL=-1
NeL+=1
numb1+=1