Why does my comprehension list do not work? - python

Hello here is my code in Python :
test = [test[i-1]+3 if i > 0 else 4 for i in range(0, 10)]
My problem is that I want to use a comprehension list for this :
test[0] = 4
test[i] = test[i-1]+3 if i > 0
I want to use a comprehension list to do this.

You don't need any kind of recursion for this. The final list you want is
[4, 7, 10, 13, ...] # 4 + 0, 4 + 3, 4 + 6, 4 + 9, ...
which you can define simply as
test = [4 + 3*i for i in range(10)]

In case you need recursion (in case of a change in formula or conditions), you can use this recursive solution:
from functools import lru_cache
#lru_cache(maxsize=None)
def f(n):
return f(n - 1) + 3 if n > 0 else 4
test = [f(i) for i in range(10)]
print(test)
Output:
[4, 7, 10, 13, 16, 19, 22, 25, 28, 31]

Another version, without recursion, using itertools.accumulate:
from itertools import accumulate
print(list(accumulate(4 if i==0 else 3 for i in range(10))))
Prints:
[4, 7, 10, 13, 16, 19, 22, 25, 28, 31]

Related

Sample irregular list of numbers with a set delta

Is there a simpler way, using e.g. numpy, to get samples for a given X and delta than the below code?
>>> X = [1, 4, 5, 6, 11, 13, 15, 20, 21, 22, 25, 30]
>>> delta = 5
>>> samples = [X[0]]
>>> for x in X:
... if x - samples[-1] >= delta:
... samples.append(x)
>>> samples
[1, 6, 11, 20, 25, 30]
If you are aiming to "vectorize" the process for performance reasons (e.g. using numpy), you could compute the number of elements that are less than each element plus the delta. This will give you indices for the items to select with the items that need to be skipped getting the same index as the preceding ones to be kept.
import numpy as np
X = np.array([1, 4, 5, 6, 11, 13, 15, 20, 21, 22, 25, 30])
delta = 5
i = np.sum(X<X[:,None]+delta,axis=1) # index of first to keep
i = np.insert(i[:-1],0,0) # always want the first, never the last
Y = X[np.unique(i)] # extract values as unique indexes
print(Y)
[ 1 6 11 20 25 30]
This assumes that the numbers are in ascending order
[EDIT]
As indicated in my comment, the above solution is flawed and will only work some of the time. Although vectorizing a python function does not fully leverage the parallelism (and is slower than the python loop), it is possible to implement the filter like this
X = np.array([1, 4, 5, 6, 10,11,12, 13, 15, 20, 21, 22, 25, 30])
delta = 5
fdelta = np.frompyfunc(lambda a,b:a if a+delta>b else b,2,1)
Y = X[X==fdelta.accumulate(X,dtype=np.object)]
print(Y)
[ 1 6 11 20 25 30]

For a given X print numbers according to the scheme

Write a function, which for a given h will print numbers according to the scheme:
every line begins with a number 2^(line_number), then next natural numbers are added, so that in each line there were as many numbers as the line number.
For example for h = 5 the expected output would be:
2
4,5
8,9,10
16,17,18,19
32,33,34,35,36
I was able only to do that:
def function():
h = 1
while h <= 5:
a = 2**h
h += 1
print(a)
return
function()
output:
2
4
8
16
32
It prints only the first numbers, no idea how to do it as required.
You can use range() to create a sequence of numbers starting from a with the desired length, and print that as the row.
def function():
for h in range(1, 6):
a = 2**h
row = range(a, a+h)
print(",".join(str(num) for num in row))
def func(val):
h=2
res = []
for i in range(1, val+1):
tmp =[h**i]
tmp +=[tmp[0]+j for j in range(1, i)]
res.append(tmp)
return res
sol = func(5)
print(sol, sep='\n')
#[[2], [4, 5], [8, 9, 10], [16, 17, 18, 19], [32, 33, 34, 35, 36]]
print(*sol, sep='\n')
"""
[2]
[4, 5]
[8, 9, 10]
[16, 17, 18, 19]
[32, 33, 34, 35, 36]
"""

Find the longest arithmetic progression inside a sequence

Suppose I have a sequence of increasing numbers, and I want to find the length of longest arithmetic progression within the sequence. Longest arithmetic progression means an increasing sequence with common difference, such as [2, 4, 6, 8] or [3, 6, 9, 12].
For example,
for [5, 10, 14, 15, 17], [5, 10, 15] is the longest arithmetic progression, with length 3;
for [10, 12, 13, 20, 22, 23, 30], [10, 20, 30] is the longest arithmetic progression with length 3;
for [7, 10, 12, 13, 15, 20, 21], [10, 15, 20] or [7, 10, 13] are the longest arithmetic progressions with length 3.
This site
https://prismoskills.appspot.com/lessons/Dynamic_Programming/Chapter_22_-_Longest_arithmetic_progression.jsp
offers some insight into the problem, i.e. by looping around j and consider
every 3 elements. I intend to use this algorithm in Python, and my code is as follows:
def length_of_AP(L):
n = len(L)
Table = [[0 for _ in range(n)] for _ in range(n)]
length_of_AP = 2
# initialise the last column of the table as all i and (n-1) pairs have lenth 2
for i in range(n):
Table[i][n-1] =2
# loop around the list and i, k such that L[i] + L[k] = 2 * L[j]
for j in range(n - 2, 0, -1):
i = j - 1
k = j + 1
while i >= 0 and k < n:
difference = (L[i] + L[k]) - 2 * L[j]
if difference < 0:
k = k + 1
else:
if difference > 0:
i = i - 1
else:
Table[i][j] = Table[j][k] + 1
length_of_AP = max(length_of_AP, Table[i][j])
k = k + 1
i = i - 1
return length_of_AP
This function works fine with [1, 3, 4, 5, 7, 8, 9], but it doesn't work for [5, 10, 14, 15, 20, 25, 26, 27, 28, 30, 31], where I am supposed to get 6 but I got 4. I can see the reason being that 25, 26, 27, 28 inside the list may be a distracting factor for my function. How do I change my function so that it gives me the result desired.
Any help may be appreciated.
Following your link and running second sample, it looks like the code actually find proper LAP
5, 10, 15, 20, 25, 30,
but fails to find proper length. I didn't spend too much time analyzing the code but the piece
// Any 2-letter series is an AP
// Here we initialize only for the last column of lookup because
// all i and (n-1) pairs form an AP of size 2
for (int i=0; i<n; i++)
lookup[i][n-1] = 2;
looks suspicious to me. It seems that you need to initialize whole lookup table with 2 instead of just last column and if I do so, it starts to get correct length on your sample as well.
So get rid of the "initialise" loop and change your 3rd line to following code:
# initialise whole table with 2 as all (i, j) pairs have length 2
Table = [[2 for _ in range(n)] for _ in range(n)]
Moreover their
Sample Execution:
Max AP length = 6
3, 5, 7, 9, 11, 13, 15, 17,
Contains this bug as well and actually prints correct sequence only because of sheer luck. If I modify the sortedArr to
int sortedArr[] = new int[] {3, 4, 5, 7, 8, 9, 11, 13, 14, 15, 16, 17, 18, 112, 113, 114, 115, 116, 117, 118};
I get following output
Max AP length = 7
112, 113, 114, 115, 116, 117, 118,
which is obviously wrong as original 8-items long sequence 3, 5, 7, 9, 11, 13, 15, 17, is still there.
Did you try it?
Here's a quick brute force implementation, for small datasets it should run fast enough:
def gen(seq):
diff = ((b-a, a) for a, b in it.combinations(sorted(seq), 2))
for d, n in diff:
k = []
while n in seq:
k.append(n)
n += d
yield (d, k)
def arith(seq):
return max(gen(seq), key=lambda x: len(x[1]))
In [1]: arith([7, 10, 12, 13, 15, 20, 21])
Out[1]: (3, [7, 10, 13])
In [2]: %timeit arith([7, 10, 12, 13, 15, 20, 21])
10000 loops, best of 3: 23.6 µs per loop
In [3]: seq = {random.randrange(1000) for _ in range(100)}
In [4]: arith(seq)
Out[4]: (171, [229, 400, 571, 742, 913])
In [5]: %timeit arith(seq)
100 loops, best of 3: 3.79 ms per loop
In [6]: seq = {random.randrange(1000000) for _ in range(1000)}
In [7]: arith(seq)
Out[7]: (81261, [821349, 902610, 983871])
In [8]: %timeit arith(seq)
1 loop, best of 3: 434 ms per loop

How do i reference values from various ranges within a list?

What I want to do is reference several different ranges from within a list, i.e. I want the 4-6th elements, the 12 - 18th elements, etc. This was my initial attempt:
test = theList[4:7, 12:18]
Which I would expect to give do the same thing as:
test = theList[4,5,6,12,13,14,15,16,17]
But I got a syntax error. What is the best/easiest way to do this?
You can add the two lists.
>>> theList = list(range(20))
>>> theList[4:7] + theList[12:18]
[4, 5, 6, 12, 13, 14, 15, 16, 17]
You can also use itertools module :
>>> from itertools import islice,chain
>>> theList=range(20)
>>> list(chain.from_iterable(islice(theList,*t) for t in [(4,7),(12,18)]))
[4, 5, 6, 12, 13, 14, 15, 16, 17]
Note that since islice returns a generator in each iteration it performs better than list slicing in terms of memory use.
Also you can use a function for more indices and a general way .
>>> def slicer(iterable,*args):
... return chain.from_iterable(islice(iterable,*i) for i in args)
...
>>> list(slicer(range(40),(2,8),(10,16),(30,38)))
[2, 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15, 30, 31, 32, 33, 34, 35, 36, 37]
Note : if you want to loop over the result you don't need convert the result to list!
You can add the two lists as #Bhargav_Rao stated. More generically, you can also use a list generator syntax:
test = [theList[i] for i in range(len(theList)) if 4 <= i <= 7 or 12 <= i <= 18]

Find common numbers in Python

I've 2 list
a = [1,9] # signifies the start point and end point, ie numbers 1,2,3,4,5,6,7,8,9
b = [4,23] # same for this.
Now I need to find whether the numbers from a intersect with numbers from b.
I can do it via making a list of numbers from a and b,and then intersecting the 2 lists, but I'm looking for some more pythonic solution.
Is there anything better solution.
My o/p should be 4,5,6,7,8,9
This is using intersecting two lists:
c = list(set(range(a[0],a[1]+1)) & set(range(b[0],b[1]+1)))
>>> print c
[4,5,6,7,8,9]
This is using min and max:
>>> c = range(max([a[0],b[0]]), min([a[1],b[1]])+1)
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
b = [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]
The most efficient way is using sets:
result = set(a).intersection(b)
Of course you can use a generator (a pythonic way of applying your logic)
result = (x for x in a if x in b)
You need to get [] or None or sth if sets do not inersect. Something like this would be most efficient:
def intersect(l1, l2):
bg = max(l1[0], l2[0])
end = max(l1[1], l2[1])
return [bg, end] if bg < end else []

Categories

Resources