A simple list simulation in python - python

lists = ['A', 'B', 'C', 'D']
nos = [4, 4, 1, 1]
for idx, ln in enumerate(zip(lists,nos)):
l, n = ln[0], ln[1]
in_nos = range(1, n+1)
for indx, in_no in enumerate(in_nos):
out_no = ??? ### **I need an expression to get out_no here**
print out_no
Without modifying anything except the ??? after out_no, I need to print out the numbers from 1 to the sum of the numbers in nos i.e.:
1
2
3
4
5
6
7
8
9
10
I tried as:
out_no = idx*n + indx + 1
which resulted in:
1
2
3
4
5
6
7
8
1
1
Which out_no would give me the correct result?

Depends on what you're allowed to change, the simple way would of course be:
lists = ['A', 'B', 'C', 'D']
nos = [4, 4, 1, 1]
a = 0
for idx, ln in enumerate(zip(lists,nos)):
l, n = ln[0], ln[1]
in_nos = range(1, n+1)
for indx, in_no in enumerate(in_nos):
out_no = a+indx+1
print out_no ##The result should be HERE
a += n
Assuming you can only change out_no, you could do:
lists = ['A', 'B', 'C', 'D']
nos = [4, 4, 1, 1]
for idx, ln in enumerate(zip(lists,nos)):
l, n = ln[0], ln[1]
in_nos = range(1, n+1)
for indx, in_no in enumerate(in_nos):
out_no = sum(nos[0:+idx])+indx+1
print out_no ##The result should be HERE
Ok, as IanAuld pointed out, if you can just scrap everything but nos there are simpler solutions, for instance:
nos = [4, 4, 1, 1]
for i in range(sum(nos)): print i+1

Related

Function to reverse every sub-array group of size k in python

I did this code so I reverse sub array group of integers but actually it only reverse the first sub array only and I don't know why this is happening!!!
Here is the code:
def reverseInGroups(self, arr, N, K):
rev=list()
count=0
reach=K
limit=0
while limit<N-1:
rev[limit:reach]=reversed(arr[limit:reach])
limit=limit+K
reach=reach+K
if reach==N-1 or reach<N-1:
continue
elif reach>N-1:
reach=N-1
return rev
This is the the input,excpected output and my output:
For Input:
5 3
1 2 3 4 5
Your Output:
1 2 3 4 5
Expected Output:
3 2 1 5 4
I tried your code online and its fine, but you have one logic error in your function to get your desired output.
while limit<N-1:
rev[limit:reach]=reversed(arr[limit:reach])
limit=limit+K #3
reach=reach+K #6
if reach==N-1 or reach<N-1:
continue
elif reach>N-1:
reach=N #5
this is an image to see what I mean image description
You don't have to create new list rev, you can reverse items in list arr. For example:
def reverseInGroups(arr, N, K):
limit = 0
while limit < N:
arr[limit : limit + K] = reversed(arr[limit : limit + K])
limit += K
return arr
l = [1, 2, 3, 4, 5]
print(reverseInGroups(l, 5, 3))
Prints:
[3, 2, 1, 5, 4]
I suggest you use this simpler solution:
arr = [1, 2, 3, 4, 5]
n = 5
k = 3
new_arr = list()
for index in range(0, n - 1, k):
new_arr[index:index+k] = arr[index:index+k][::-1]
print(new_arr)
And the output is:
[3, 2, 1, 5, 4]
After putting this code in your function, it is as below:
def reverseInGroups(self, arr, n, k):
new_arr = list()
for index in range(0, n - 1, k):
new_arr[index:index+k] = arr[index:index+k][::-1]
return new_arr
we can do the loop in the increment of K and then reverse the array of that specific size
def reverseInGroups(self, arr, N, K):
# code here
for i in range(0, N -1 , K):
arr[i:i +K] = arr[i:i +K][::-1]

How to get ranks from a sample in a list of values?

I'm new with Python and have a quite simple problem on paper but difficult to me in Python.
I have two samples of values (which are lists) :
X = [2, 2, 4, 6]
Y = [1, 3, 4, 5]
I have a concatenated list which is sorted as
Z = [ 1 , 2 , 2 , 3 , 4 , 4 , 5 , 6]
#rank: 1 2.5 4 5.5 7 8
I would like to get the sum of ranks of X values in Z. For this example, the ranks of 2, 2, 4 and 6 in Z are 2.5 + 2.5 + 5.5 + 8 = 18.5
(ranks of Y values in Z are 1 + 4 + 5.5 + 7 = 17.5)
Here is what I've done but it doesn't work with these lists X and Y (it works if each value appears only one time)
def funct(X, Z):
rank = []
for i in range(len(Z)):
for j in range(len(X)):
if Z[i] == X[j]:
rank = rank + [(i+1)]
print(sum(rank))
return
I would like to solve my problem with not too much complicated functions (only loops and quite easy ways to get a solution).
You can use a dictionary to keep track of the rank sums and counts once you've sorted the combined list.
X = [2, 2, 4, 6]
Y = [1, 3, 4, 5]
Z = sorted(X + Y)
ranksum = {}
counts = {}
for i, v in enumerate(Z):
ranksum[v] = ranksum.get(v, 0) + (i + 1) # Add
counts[v] = counts.get(v, 0) + 1 # Increment count
Then, when you want to look up the rank of an element, you need ranksum[v] / count[v].
r = [ranksum[x] / counts[x] for x in X]
print(r)
# Out: [2.5, 2.5, 5.5, 8]
Here's a solution for how to build the list of ranks:
X = ...
Y = ...
Z = sorted(X + Y)
rank = [1]
z = Z[:1]
for i, e in enumerate(Z[1:], start=2):
if e == z[-1]:
rank[-1] += 0.5
else:
rank.append(i)
z.append(e)
Now you can convert that into a dictionary:
ranks = dict(zip(z, rank))
That will make lookup easier:
sum(ranks[e] for e in X)
Here's another option where you build a dictionary of the rank indexes and then create a rank dictionary from there:
from collections import defaultdict
X = [2, 2, 4, 6]
Y = [1, 3, 4, 5]
Z = sorted(X + Y)
rank_indexes = defaultdict(lambda: [])
for i,v in enumerate(Z):
rank_indexes[v].append(i+1)
ranks = {k:(sum(v)/len(v)) for (k,v) in rank_indexes.items()}
print("Sum of X ranks:", sum([ranks[v] for v in X]))
print("Sum of Y ranks:", sum([ranks[v] for v in Y]))
Output:
Sum of X ranks: 18.5
Sum of Y ranks: 17.5
You can do the same thing without defaultdict, but it's slightly slower and I'd argue less Pythonic:
rank_indexes = {}
for i,v in enumerate(Z):
rank_indexes.setdefault(v, []).append(i+1)
ranks = {k:(sum(v)/len(v)) for (k,v) in rank_indexes.items()}

Reassigning numpy.array()

In the code below, I can easily reduce the array ['a','b','a','c','b','b','c','a'] to a binary array [0 1 0 1 1 1 1 0] so that 'a' -> 0 and 'b','c' -> 1. How do I transform it to a ternary array so that 'a' -> 0, 'b' -> 1, 'c' -> 2, without using for and if-else? Thanks.
import numpy as np
x = np.array(['a', 'b', 'a', 'c', 'b', 'b', 'c', 'a'])
y = np.where(x=='a', 0, 1)
print(y)
By doing:
np.where(x == 'a', 0, (np.where(x == 'b', 1, 2)))
note that this changes all the characters that are neither 'a' or 'b' to 2. I've assumed that you have only an array with a,b and c.
A more scalable version is using dictionary of conversion:
my_dict = {'a':0, 'b':1, 'c':2}
x = np.vectorize(my_dict.get)(x)
output:
[0 1 0 2 1 1 2 0]
Another approach is:
np.select([x==i for i in ['a','b','c']], np.arange(3))
For small dictionary #ypno's answer is going to be faster. For larger dictionary, use this answer.
Time Comparison:
Ternary alphabet:
lst = ['a','b','c']
my_dict = {k: v for v, k in enumerate(lst)}
##Ehsan's solution1
def m1(x):
return np.vectorize(my_dict.get)(x)
##ypno's solution
def m2(x):
return np.where(x == 'a', 0, (np.where(x == 'b', 1, 2)))
##SteBog's solution
def m3(x):
y = np.where(x=='a', 0, x)
y = np.where(x=='b', 1, y)
y = np.where(x=='c', 2, y)
return y.astype(np.integer)
##Ehsan's solution 2 (also suggested by user3483203 in comments)
def m4(x):
return np.select([x==i for i in lst], np.arange(len(lst)))
##juanpa.arrivillaga's solution suggested in comments
def m5(x):
return np.array([my_dict[i] for i in x.tolist()])
in_ = [np.random.choice(lst, size = n) for n in [10,100,1000,10000,100000]]
Same analysis for 8 letter alphabet:
lst = ['a','b','c','d','e','f','g','h']

Implementing k nearest neighbours from distance matrix?

I am trying to do the following:
Given a dataFrame of distance, I want to identify the k-nearest neighbours for each element.
Example:
A B C D
A 0 1 3 2
B 5 0 2 2
C 3 2 0 1
D 2 3 4 0
If k=2, it should return:
A: B D
B: C D
C: D B
D: A B
Distances are not necessarily symmetric.
I am thinking there must be something somewhere that does this in an efficient way using Pandas DataFrames. But I cannot find anything?
Homemade code is also very welcome! :)
Thank you!
The way I see it, I simply find n + 1 smallest numbers/distances/neighbours for each row and remove the 0, which would then give you n numbers/distances/neighbours. Keep in mind that the code will not work if you have a distance of zeroes! Only the diagonals are allowed to be 0.
import pandas as pd
import numpy as np
X = pd.DataFrame([[0, 1, 3, 2],[5, 0, 2, 2],[3, 2, 0, 1],[2, 3, 4, 0]])
X.columns = ['A', 'B', 'C', 'D']
X.index = ['A', 'B', 'C', 'D']
X = X.T
for i in X.index:
Y = X.nsmallest(3, i)
Y = Y.T
Y = Y[Y.index.str.startswith(i)]
Y = Y.loc[:, Y.any()]
for j in Y.index:
print(i + ": ", list(Y.columns))
This prints out:
A: ['B', 'D']
B: ['C', 'D']
C: ['D', 'B']
D: ['A', 'B']

python compare items in 2 list of different length - order is important

list_1 = ['a', 'a', 'a', 'b']
list_2 = ['a', 'b', 'b', 'b', 'c']
so in the list above, only items in index 0 is the same while index 1 to 4 in both list are different. also, list_2 has an extra item 'c'.
I want to count the number of times the index in both list are different, In this case I should get 3.
I tried doing this:
x = 0
for i in max(len(list_1),len(list_2)):
if list_1[i]==list_2[i]:
continue
else:
x+=1
I am getting an error.
Use the zip() function to pair up the lists, counting all the differences, then add the difference in length.
zip() will only iterate over the items that can be paired up, but there is little point in iterating over the remainder; you know those are all to be counted as different:
differences = sum(a != b for a, b in zip(list_1, list_2))
differences += abs(len(list_1) - len(list_2))
The sum() sums up True and False values; this works because Python's boolean type is a subclass of int and False equals 0, True equals 1. Thus, for each differing pair of elements, the True values produced by the != tests add up as 1s.
Demo:
>>> list_1 = ['a', 'a', 'a', 'b']
>>> list_2 = ['a', 'b', 'b', 'b', 'c']
>>> sum(a != b for a, b in zip(list_1, list_2))
2
>>> abs(len(list_1) - len(list_2))
1
>>> difference = sum(a != b for a, b in zip(list_1, list_2))
>>> difference += abs(len(list_1) - len(list_2))
>>> difference
3
You can try with this :
list1 = [1,2,3,5,7,8,23,24,25,32]
list2 = [5,3,4,21,201,51,4,5,9,12,32,23]
list3 = []
for i in range(len(list2)):
if list2[i] not in list1:
pass
else :
list3.append(list2[i])
print list3
print len(list3)
As ZdaR commented, you should get 3 as the result and zip_longest can help here if you don't have Nones in the lists.
from itertools import zip_longest
list_1=['a', 'a', 'a', 'b']
list_2=['a', 'b', 'b', 'b', 'c']
x = sum(a != b for a,b in zip_longest(list_1,list_2))
Can i try this way using for loop:
>>> count = 0
>>> ls1 = ['a', 'a', 'a', 'b']
>>> ls2 = ['a', 'b', 'b', 'b', 'c']
>>> for i in range(0, max(len(ls1),len(ls2)), 1):
... if ls1[i:i+1] != ls2[i:i+1]:
... count += 1
...
>>> print count
3
>>>
Or try this (didn't change the lists):
dif = 0
for i in range(len(min(list_1, list_2))):
if list_1[i]!=list_2[i]:
dif+=1
#print(list_1[i], " != ", list_2[i], " --> Dif = ", dif)
dif+=(len(max(list_1, list_2)) - len(min(list_1, list_2)))
print("Difference = ", dif)
(Output: Difference = 3)
Not much better, but here's another option
if len(a) < len(b):
b = b[0:len(a)]
else:
a = a[0:len(b)]
correct = sum(a == b)

Categories

Resources