Loop through list to extract specific patterns - python

I have a quite specific question that I'm unsure about how to go forward with.
I have a list of numbers and I want to extract some specific patterns from them where I loop through the list and create a new one, it's easier to explain with an example.
Say I have a list, a = [2, 9, 3, 2, 3, 5, 7, 9].
What I want to do with this list is loop through 4 numbers at a time and give them corresponding letters, depending on when they occur in the sequence.
i.e. First four numbers = 2932 = ABCA
Second sequence of numbers = 9323 = ABCB
Third sequence = 3235 = ABAC
Fourth sequence = 2357 = ABCD
Fifth sequence = 3579 = ABCD
I then want to take these sequences and add them to another list which would now look like,
b = [ABCA, ABCB, ABAC, ABCD, ABCD]
I'm really unsure about how the format of the code should be, the length of the new list will always be 3 less than the original. Any help would be great, thanks.

You can use a dictionary to assign letters to numbers and read that dictionary again to access the relevant letters. It has 2 loops, which is not ideal but it does the job:
a = [2, 9, 3, 2, 3, 5, 7, 9]
len_a = len(a)
output = []
letters = 'ABCD'
for i in range(len_a-3):
d = {}
k = 0
for j in a[i:i+4]:
if j not in d:
d[j] = letters[k]
k += 1
else:
continue
letter_assignment = ''.join([d[j] for j in a[i:i+4]])
output.append(letter_assignment)
Output:
print(output)
# ['ABCA', 'ABCB', 'ABAC', 'ABCD', 'ABCD']

I recommend using zip function for corresponding the numbers with the letters, while for the loop, use the "for" function.

Related

find the second largest number in the given list [duplicant]

b=list(map(int,input().split()))
c=max(b)
for i in b:
if i == c:
b.remove(i)
else:
continue
print(max(b))
where I am getting wrong with this code I am not getting correct output for input 6 4 5 6 6
We can use a set and sorted() to grab the second highest number in the list.
Passing your list to a set will only include unique numbers
We then sort the set and grab the second last element in the list
data = [6, 4, 5, 6, 6]
sorted(set(data))[-2]
#5
First Approach
In this code, we are sorting the list b and then printing the second-last value using indexing
b=list(map(int,input().split()))
sorted(b)
print(b[-2])
Output:
6
Second Approach
In this approach, we are sorting the list, converting it to a set to remove duplicate values, converting the set again into a list and getting the second-last value
b=list(map(int,input().split()))
sorted(b)
final_b = list(set(b))
print(final_b[-2])
Output
5
Actually, the above codes can be written in a single line / fewer lines but it won't be easy for you to read if you are a beginner.
b = list(set(map(int, input().split())))
b.sort()
print(None if len(b) < 2 else b[-2])
set is used to delete duplicate values, and finally to determine if there are two numbers.
A different approach would be to use the nlargest method of the heapq module. it can be used to find the first n largest numbers
import heapq
data = [6, 4, 5, 6, 6]
heapq.nlargest(2, set(data)) # returns [6, 5]
# So we can unpack the values as below
_, second_max = heapq.nlargest(2, set(data)) # the '_' means we dont care about storing that variable
# Now print it
print(second_max) # Output: 5

Repeating same code block for creating different values

I'm making a program that basically calculates the missing values (x in this example) in multiple lists.
These are the lists:
L11=[1,3,5,'x',8,10]
L12=['x',3,3,'x',6,0]
L21=[6,1,1,9,2,2]
L22=[1,1,1,'x','x','x']
For example, I'm using this code block to find the x values in L22:
#How to find x:
#1--> a= calculate the sum of integers in the list
#2--> b=calculate the average of them
#3--> all values of x inside the list equal b
a22=L22.count('x')
for i in range(len(L22)):
if L22[i]=='x':
x_L22=round((sum([int(k) for k in L22 if type(k)==int]))/(len(L22)-a22))
So we find x_L22=1 and the new L22 is:
x_L22=1
L22=[1,1,1,1,1,1]
Now here is my question, I want to repeat this steps for all other lists without writing the same code. Is this possible?
Other answers focus on extracting your current code to a generic function which is useful but isn't neither sufficient nor necessary to apply the same piece of code on multiple input.
The only thing you need is to loop over your pieces of data :
L11=[1,3,5,'x',8,10]
L12=['x',3,3,'x',6,0]
L21=[6,1,1,9,2,2]
L22=[1,1,1,'x','x','x']
inputs = ( L11, L12, L21, L22 )
for input in inputs :
# your 4 previous lines on code, modified to work
# on the generic "input" instead of the specific "L22"
a=input.count('x')
for i in range(len(input)):
if input[i]=='x':
x=round((sum([int(k) for k in input if type(k)==int]))/(len(input)-a))
# or if you've extracted the above code to a function,
# just call it instead of using the above 4 lines of code.
try putting it in a function like this:
def list_foo(list_):
counted=list_.count('x')
for i in range(len(list_)):
if list_[i]=='x':
total=round((sum([int(k) for k in list_ if type(k)==int])) \
/(len(list_)-counted))
return total
use it in your main loop
x_L22 = list_foo(L22)
or x_L11 = list_foo(L11)
This is an excellent use case for functions in Python
def get_filled_list(list_of_numbers):
#How to find x:
#1--> a= calculate the sum of integers in the list
#2--> b=calculate the average of them
#3--> all values of x inside the list equal b
new_list=list_of_numbers.count('x')
for i in range(len(list_of_numbers)):
if list_of_numbers[i]=='x':
list_of_numbers = round(
(sum([int(k)
for k in list_of_numbers if type(k)==int]))/
(len(list_of_numbers)-new_list)
)
A11 = get_filled_list(L11)
# ,..
I'd write a function that receives a list as an input and returns the same list with the 'x' value replaced with a new value:
def calculateList(l):
nrX=l.count('x')
newList = []
for elem in l:
if elem == 'x':
x = int(round((sum([int(k) for k in l if type(k)==int]))/(len(l)-nrX)))
newList.append(x)
else:
newList.append(elem)
return newList
You can then call this function on all the list you have:
newL = calculateList(L22)
print(newL)
Output is:
[1, 1, 1, 1, 1, 1]
Or if you prefer you can create a list containing all the lists you want to evaluate:
allLists = [L11, L12, L21, L22]
And then you iterate over this list:
for l in allLists:
newL = calculateList(l)
print(newL)
Output is:
[1, 3, 5, 5, 8, 10]
[3, 3, 3, 3, 6, 0]
[6, 1, 1, 9, 2, 2]
[1, 1, 1, 1, 1, 1]

Identify least common number in a list python

With a list of numbers, each number can appear multiple times, i need to find the least common number in the list. If different numbers have the same lowest frequency, the result is the one occurring last in the list. An example, the least common integer in [1, 7, 2, 1, 2] is 7 (not 2, as originally said). And the list needs to stay unsorted
I have the following but it always sets the last entry to leastCommon
def least_common_in_unsorted(integers):
leastCommon = integers[0]
check = 1
appears = 1
for currentPosition in integers:
if currentPosition == leastCommon:
appears + 1
elif currentPosition != leastCommon:
if check <= appears:
check = 1
appears = 1
leastCommon = currentPosition
return leastCommon
Any help would be greatly appreciated
It is the simplest way come in my mind right now:
a = [1, 7, 2, 1, 2]
c, least = len(a), 0
for x in a:
if a.count(x) <= c :
c = a.count(x)
least = x
least # 7
and in two least items it will return the last occurrence one.
a = [1, 7, 2, 1, 2, 7] # least = 7
Using the Counter:
from collections import Counter
lst = [1, 7, 2, 1, 2]
cnt = Counter(lst)
mincnt = min(cnt.values())
minval = next(n for n in reversed(lst) if cnt[n] == mincnt)
print(minval) #7
This answer is based on #offtoffel to incorporate multiple items of the same number of occurrences while choosing the last occurring one:
def least_common(lst):
return min(lst, key=lambda x: (lst.count(x), lst[::-1].index(x)))
print(least_common([1,2,1,2]))
# 2
print(least_common([1,2,7,1,2]))
# 7
Edit: I noticed that there’s a even simpler solution, that is efficient and effective (just reverse the list in the beginning and min will keep the last value that has the minimum count):
def least_common(lst):
lst = lst[::-1]
return min(lst, key=lst.count)
print(least_common([1,2,1,2]))
# 2
print(least_common([1,2,7,1,2]))
# 7
Short but inefficient:
>>> min(a[::-1], key=a.count)
7
Efficient version using collections.Counter:
>>> min(a[::-1], key=Counter(a).get)
7
def least_common(lst):
return min(set(lst), key=lst.count)
Edit: sorry, this does not always take the last list item with least occurancy, as demanded by the user...it works on the example, but not for every instance.

How do you check if a list has repeated variable in python?

I'm trying to generate a random list of 7 values and want to check the list for duplicate numbers and remove those from the list. I currently have:
import random
acard1 = random.randrange(0,13,1)
acard2 = random.randrange(0,13,1)
acard3 = random.randrange(0,13,1)
acard4 = random.randrange(0,13,1)
acard5 = random.randrange(0,13,1)
acard6 = random.randrange(0,13,1)
acard7 = random.randrange(0,13,1)
myhand=[acard1, acard2, acard3, acard4, acard5, acard6, acard7]
print(myhand)
How would I check if there are repeated values and then remove those values?
For example, if my list were [11, 7, 11, 12, 9, 9, 10],
how would I have my program recognize that 11 and 9 are repeated and turn the list into [7, 12, 10]?
Here's a simple technique using collections.Counter:
In [451]: from collections import Counter
In [453]: c = Counter(l)
In [454]: [x for x in l if c[x] == 1]
Out[454]: [7, 12, 10]
Any answers with a list comprehension using l.count(x) are definitely going to be slower than this.
Maybe create a list where you keep unique entries by checking if index number is taken? Make index 1 contain the number 1, index 2 contains number 2, and so on.
Alternatively you could search through the entire list to check if 11 is already present somewhere. Depending on language and type of list, you could delete the element at the specific index, og simply append to a new "unique" list as i attempted to describe above.

Given an index in a flattened list, get the index of the original list item

I begin with a list of words like ["ONE","TWO","THREE","FOUR"].
Later, I flatten the list to make a string: "ONETWOTHREEFOUR". I do some stuff while looking at this string and get a list of indices, say [6,7,8,0,4] (which maps onto that string to give me the word "THROW", though as pointed out in comments that's irrelevant to my question).
Now I want to know which items from the original list gave me the letters I am using to make my word. I know I used letters [6,7,8,0,4] from the joined string.
Based on that list of string indices, I want the output [0,1,2], because indexes 6, 7 and 8 in the flattened string fall within the word at index 2 in the original list, index 0 comes from the word at index 0, and index 4 falls within the word at index 1. My output doesn't include 3, because none of the indices I used fall within the final four-character word.
What I've tried so far:
wordlist = ["ONE","TWO","THREE","FOUR"]
stringpositions = [6,7,8,0,4]
wordlengths = tuple(len(w) for w in wordlist) #->(3, 3, 5, 4)
wordstarts = tuple(sum(wordlengths[:i]) for i in range(len(wordlengths))) #->(0, 3, 6, 11)
words_used = set()
for pos in stringpositions:
prev = 0
for wordnumber,wordstart in enumerate(wordstarts):
if pos < wordstart:
words_used.add(prev)
break
prev = wordnumber
It seems awfully long-winded. What's the best (and/or most Pythonic) way for me to do this?
As clarified in the comments, the OP's goal is to figure out which words were used based on which string positions were used, rather than which letters were used -- so the word/substring THROW is basically irrelevant.
Here's a very short version:
from itertools import chain
wordlist = ["ONE","TWO","THREE","FOUR"]
string = ''.join(wordlist) # "ONETWOTHREEFOUR"
stringpositions = [6,7,8,0,4]
# construct a list that maps every position in string to a single source word
which_word = list(chain( [ii]*len(w) for ii, w in enumerate(wordlist) ))
# it's now trivial to use which_word to construct the set of words
# represented in the list stringpositions
words_used = set( which_word[pos] for pos in stringpositions )
print "which_word=", which_word
print "words_used=", words_used
==>
which_word= [0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3]
words_used= set([0, 1, 2])
EDIT: Updated to use list(itertools.chain(generator)) rather than sum(generator, []) as suggested by #inspectorG4dget in the comments.
Here's the easiest way. If you want to be more space-efficient, you might want to use some sort of binary search tree
wordlist = ["ONE","TWO","THREE","FOUR"]
top = 0
inds = {}
for i,word in enumerate(wordlist):
for k in range(top, top+len(word)):
inds[k] = i
top += len(word)
#do some magic
L = [6,7,8,0,4]
for i in L: print(inds[i])
Output:
2
2
2
0
1
You could of course call set() on the output if you wanted to

Categories