counting a permutation 4 characters long with 2 characters on each result - python

from itertools import permutations
perm=permutations(['A','B','C','C','D','D','D','D'],4)
for i in perm:
print (i)
how could I print a permutation of which the value in perm only prints a series of letters with 2 characters (pardon my English)
example : ADDD,DADD,BDDD,CCDD,CDDD etc (only 2 characters for every permutation)

I think for this you will have to generate all combinations, and filter down to the condition you want.
Keep this bit the same:
from itertools import permutations
perm = permutations(['A', 'B', 'C', 'C', 'D', 'D', 'D', 'D'], 4)
But then keep only the elements which satisfy your condition, by using list comprehension. Convert the element to a set, and count the length of the set. An element like ('A', 'B', 'B') gets converted to {'A', 'B'}.
perm = [x for x in perm if len(set(x))==2]

for i in perm:
if len((set(list(i))) == 2:
print (i)
lets say i is ABAA
list(i) will result in [A,B,A,A]
set() of that will result in {A,B}
then len() of that will be 2

Related

List of index where corresponding elements of two lists are same

I want to compare two different lists and return the indexes of similar stings.
For example, if I have two lists like:
grades = ['A', 'B', 'A', 'E', 'D']
scored = ['A', 'B', 'F', 'F', 'D']
My expected output is:
[0, 1, 4] #The indexes of similar strings in both lists
However this is the result I am getting at the moment:
[0, 1, 2, 4] #Problem: The 2nd index being counted again
I have tried coding using using two approaches.
First Approach:
def markGrades(grades, scored):
indices = [i for i, item in enumerate(grades) if item in scored]
return indices
Second Approach:
def markGrades(grades, scored):
indices = []
for i, item in enumerate(grades):
if i in scored and i not in indices:
indices.append(i)
return indices
The second approach returns correct strings but not the indexes.
You can use enumerate along with zip in list comprehension to achieve this as:
>>> grades = ['A', 'B', 'A', 'E', 'D']
>>> scored = ['A', 'B', 'F', 'F', 'D']
>>> [i for i, (g, s) in enumerate(zip(grades, scored)) if g==s]
[0, 1, 4]
Issue with your code is that you are not comparing the elements at the same index. Instead via using in you are checking whether elements of one list are present in another list or not.
Because 'A' at index 2 of grades is present in scored list. You are getting index 2 in your resultant list.
Your logic fails in that it doesn't check whether the elements are in the same position, merely that the grades element appears somewhere in scored. If you simply check corresponding elements, you can do this simply.
Using your second approach:
for i, item in enumerate(grades):
if item == scored[i]:
indices.append(i)
The solution that Anonymous gives is what I was about to add as the "Pythonic" way to solve the problem.
You can access the two lists in pairs (to avoid the over-generalization of finding a match anywhere in the other array) with zip
grades = ['A', 'B', 'A', 'E', 'D']
scored = ['A', 'B', 'F', 'F', 'D']
matches = []
for ix, (gr, sc) in enumerate(zip(grades,scored)):
if gr == sc:
matches.append(ix)
or more compactly with list comprehension, if that suits your purpose
matches = [ix for ix, (gr, sc) in enumerate(zip(grades,scored)) if gr == sc]

How to order an array and count it in Python?

I want to find only the top 3 distinct items in descending order. If there's a tiebreaker, sort by alphabetical order. If there are 3 items or fewer, returning the distinct list of items is sufficient.
So if I have input of: ["a","a","b","b","c","c","c","d","d","d","d"]
The output will be ["d","c","a"]
Because d has 4 counts, c 3 counts, a and b have the same frequency, but a is alphabetically first.
In MySQL, I would usually use this:
SELECT id, COUNT(*) as frequency FROM mylist GROUP BY id ORDER BY frequency, id
How can I do that in Python?
I use this code based on SAI SANTOH CHIRAG's solution:
def main(output):
arr = sorted(output,key=lambda i:[output.count(i),-ord(i)],reverse=True)
out = []
for i in arr:
if i not in out: out.append(i)
print(out[:3])
but why is the result like this:
Input (stdin) = a a a b b c d d d d
output = ['d']
['d']
['d']
['d']
['d', 'a']
['d', 'a']
['d', 'a']
['d', 'a', 'b']
['d', 'a', 'b']
['d', 'a', 'b']
instead of what I want, which would be:
['d','a','b']
You use sorted and key for that. Try in this way:
arr = sorted(x,key=lambda i:[x.count(i),-ord(i)],reverse=True)
With this you get all the elements in the sorted order in the increase of count and then alphabetical order. Then do this to get all elements only once:
out = []
for i in arr:
if i not in out:
out.append(i)
print(out[:3])
collections.Counter will do:
the_list = ["a","a","b","b","c","c","c","d","d","d","d"]
counter = Counter(sorted(the_list))
top_3 = counter.most_common(3)
at this point, top_3 is of the form [(<entry>, <freq>)] e.g.
[('d', 4), ('c', 3), ('a', 2)]
Take out the first elements from it via list comprehension:
result = [item for item, freq in top_3]
and we get
['d', 'c', 'a']
Notes:
We pass the sorted list to the Counter because otherwise it will break the ties according to the insertion order; sorting forces the insertion order to be the alphabetical order in a way.
.most_common(3) will return at most 3 elements so we are fine e.g. even if only 2 unique entries are there. E.g. if the_list = ["b", "a"], result will be ["a", "b"] even though number of unique elements is less than 3.
you can use Counter from collections
from collections import Counter
inputs = ["a","a","b","b","c","c","c","d","d","d","d"]
counts = Counter(x)
counts.most_common(3)
final = [i[0] for i in counts.most_common]
output for counts.most_common()
[('d', 4), ('c', 3), ('a', 2), ('b', 2)]
Simpler and more efficient than the accepted answer.
>>> a = ["a","a","b","b","c","c","c","d","d","d","d"]
>>> sorted(set(a), key=lambda s: (-a.count(s), s))[:3]
['d', 'c', 'a']
This removes duplicates first and thus counts each string only once. Also, much better to simply negate the count instead of the character code and using reverse sorting. If the strings had multiple characters, you couldn't even use the character code at all.
Another, using two simpler sorts (might actually be faster):
>>> sorted(sorted(set(a)), key=a.count, reverse=True)[:3]
['d', 'c', 'a']

Print random strings from a list (multiple times) with no repeats

I want to print random strings from the same list multiple times throughout the program, but without repeating any of the previously printed random strings.
If I had the following:
core = 'a', 'b', 'c', 'd'
print (random.sample(core[0:], k=2))
print (random.sample(core[0:], k=2))
I'd like the outcome to look something like:
b, d
c, a
random.sample itself works without replacement, so there is no case of repetition. Get a sample of 4 and slice:
randoms = random.sample(core, 4)
print(randoms[:2])
print(randoms[2:])
You can use shuffle() from random. Then use slicing to extract necessary elements.
import random
initial = 'a', 'b', 'c', 'd'
l = list(initial)
random.shuffle(l)
print (l[:2])
print (l[2:])
Output:
['a', 'c']
['b', 'd']

Creating an irregular list of lists from a single list

I'm trying to create a list of lists from a single list. I'm able to do this if the new list of lists have the same number of elements, however this will not always be the case
As said earlier, the function below works when the list of lists have the same number of elements.
I've tried using regular expressions to determine if an element matches a pattern using
pattern2=re.compile(r'\d\d\d\d\d\d') because the first value on my new list of lists will always be 6 digits and it will be the only one that follows that format. However, i'm not sure of the syntax of getting it to stop at the next match and create another list
def chunks(l,n):
for i in range(0,len(l),n):
yield l[i:i+n]
The code above works if the list of lists will contain the same number of elements
Below is what I expect.
OldList=[111111,a,b,c,d,222222,a,b,c,333333,a,d,e,f]
DesiredList=[[111111,a,b,c,d],[222222,a,b,c],[333333,a,d,e,f]]
Many thanks indeed.
Cheers
Likely a much more efficient way to do this (with fewer loops), but here is one approach that finds the indexes of the breakpoints and then slices the list from index to index appending None to the end of the indexes list to capture the remaining items. If your 6 digit numbers are really strings, then you could eliminate the str() inside re.match().
import re
d = [111111,'a','b','c','d',222222,'a','b','c',333333,'a','d','e','f']
indexes = [i for i, x in enumerate(d) if re.match(r'\d{6}', str(x))]
groups = [d[s:e] for s, e in zip(indexes, indexes[1:] + [None])]
print(groups)
# [[111111, 'a', 'b', 'c', 'd'], [222222, 'a', 'b', 'c'], [333333, 'a', 'd', 'e', 'f']]
You can use a fold.
First, define a function to locate the start flag:
>>> def is_start_flag(v):
... return len(v) == 6 and v.isdigit()
That will be useful if the flags are not exactly what you expected them to be, or to exclude some false positives, or even if you need a regex.
Then use functools.reduce:
>>> L = d = ['111111', 'a', 'b', 'c', 'd', '222222', 'a', 'b', 'c', '333333', 'a', 'd', 'e', 'f']
>>> import functools
>>> functools.reduce(lambda acc, x: acc+[[x]] if is_start_flag(x) else acc[:-1]+[acc[-1]+[x]], L, [])
[['111111', 'a', 'b', 'c', 'd'], ['222222', 'a', 'b', 'c'], ['333333', 'a', 'd', 'e', 'f']]
If the next element x is the start flag, then append a new list [x] to the accumulator. Else, add the element to the current list, ie the last list of the accumulator.

choosing random values but have each value chosen an exact number of times

i'm new to python.
I have a list of four values.
I need to choose random values from this list 32 times.
However, I need that each value be chosen exactly 8 times.
so far I used this:
import random
my_list=['a','b','c','d']
for i in range(1,33):
selection=random.choice(my_list)
print("{} selection: {}".format(i,selection))
This works - but how do I get it to give me each value exactly 8 times?
Thanks for helping.
I would build a list with the required elements in it, then shuffle it.
import random
my_list = ['a', 'b', 'c', 'd'] * 8
random.shuffle(my_list)
Now my_list contains 32 elements in random order, with each unique element appearing eight times.
You can first multiply your list 8 times
>>> result = my_list*8
Then random.shuffle that list and str.join it.
>>> random.shuffle(result)
>>> print(''.join(result))
aaabdddbcdbcbabadcccddabbacbaccd
In order to ensure that each value is selected at 8 times for each element in your list you're going to need a counter for each element. You'll need to keep track of how many times each element has been selected.
Every time that choice is letter is randomly selected increment its unique counter by 1. When you run your random selection again you'll need to check if that value has been selected 8 times already. If it has toss that selection and run the random selection again. Then you'll need to check and see if its randomly returned result has been selected 8 times already.
Write a nested for loop, in which the outer for loop runs 8 times, and the inner for loop runs 4 times for the list of numbers. then in the list remove the value each time the for loop runs.
for i in range(1,8):
my_list = ['a','b','c','d']
for j in range(1,4):
rand = randint(1,(5-j))
print(rand)
my_list.remove([rand])
this is how I would do it, may not be the most efficient method, but you get the idea.
Create copies of each element with the multiply operator and then use random.shuffle to randomise the list elements:
>>> import random
>>> timesToSelectValue=8
>>> my_list=['a','b','c','d']
>>> new_list=my_list*timesToSelectValue
>>> random.shuffle(new_list)
>>> print(new_list)
['d', 'b', 'd', 'a', 'c', 'b', 'b', 'a', 'b', 'd', 'd', 'b', 'c', 'b', 'a', 'b', 'c', 'd', 'd', 'c', 'a', 'a', 'b', 'c', 'a', 'c', 'd', 'c', 'd', 'c', 'a', 'a']
new_list is now in a random order and contains exactly 8 of each element in my_list:
>>> for i in my_list:
... print("count {}={}".format(i,new_list.count(i)))
...
count a=8
count b=8
count c=8
count d=8

Categories