How to pick a sequence of numbers from a list? - python

I have a startnumber and an endnumber.
From these numbers I need to pick a sequence of numbers.
The sequences is not always the same.
Example:
startnumber = 1
endnumber = 32
I need to create a list of numbers with a certain sequence
p.e.
3 numbers yes, 2 numbers no, 3 numbers yes, 2 numbers no.. etc
Expected output:
[[1-3],[6-8],[11-13],[16-18],[21-23],[26-28],[31-32]]
(at the end there are only 2 numbers remaining (31 and 32))
Is there a simple way in python to select sequences of line from a range of numbers?

numbers = range(1,33)
take = 3
skip = 2
seq = [list(numbers[idx:idx+take]) for idx in range(0, len(numbers),take+skip)]

Extrapolating this out:
def get_data(data, filterfunc=None):
if filterfunc is None:
filterfunc = lambda: True # take every line
result = []
sub_ = []
for line in data:
if filterfunc():
sub_.append(line)
else:
if sub_:
result.append(sub_)
sub_ = []
return result
# Example filterfunc
def example_filter(take=1, leave=1):
"""example_filter is a less-fancy version of itertools.cycle"""
while True:
for _ in range(take):
yield True
for _ in range(leave):
yield False
# Your example
final = get_data(range(1, 33), example_filter(take=3, leave=2))
As alluded to in the docstring of example_filter, the filterfunc for get_data is really just expecting a True or False based on a call. You could change this easily to be of the signature:
def filterfunc(some_data: object) -> bool:
So that you can determine whether to take or leave based on the value (or even the index), but it currently takes no arguments and just functions as a less magic itertools.cycle (since it should return its value on call, not on iteration)

from itertools import islice
def grouper(iterable, n, min_chunk=1):
it = iter(iterable)
while True:
chunk = list(islice(it, n))
if len(chunk) < min_chunk:
return
yield chunk
def pick_skip_seq(seq, pick, skip, skip_first=False):
if skip_first:
ret = [ x[skip:] for x in grouper(seq, pick+skip, skip+1) ]
else:
ret = [ x[:pick] for x in grouper(seq, pick+skip) ]
return ret
pick_skip_seq(range(1,33), 3, 2) gives required list.
In pick_skip_seq(seq, pick, skip, skip_first=False),
seq is sequence to pick/skip from,
pick/skip are no. of elements to pick/skip,
skip_first is to be set True if
such behavior is desired.
grouper returns chunks of n elements, it
ignores last group if it has less
than min_chunk elements.
It is derived from stuff given in
https://stackoverflow.com/a/8991553/1921546.
Demo:
# pick 3 skip 2
for i in range(30,35):
print(pick_skip_seq(range(1,i), 3, 2))
# skip 3 pick 2
for i in range(30,35):
print(pick_skip_seq(range(1,i), 3, 2, True))
An alternative implementation of pick_skip_seq:
from itertools import chain,cycle,repeat,compress
def pick_skip_seq(seq, pick, skip, skip_first=False):
if skip_first:
c = cycle(chain(repeat(0, skip), repeat(1, pick)))
else:
c = cycle(chain(repeat(1, pick), repeat(0, skip)))
return list(grouper(compress(seq, c), pick))
All things used are documented here: https://docs.python.org/3/library/itertools.html#itertools.compress

Related

Find the nth lucky number generated by a sieve in Python

I'm trying to make a program in Python which will generate the nth lucky number according to the lucky number sieve. I'm fairly new to Python so I don't know how to do all that much yet. So far I've figured out how to make a function which determines all lucky numbers below a specified number:
def lucky(number):
l = range(1, number + 1, 2)
i = 1
while i < len(l):
del l[l[i] - 1::l[i]]
i += 1
return l
Is there a way to modify this so that I can instead find the nth lucky number? I thought about increasing the specified number gradually until a list of the appropriate length to find the required lucky number was created, but that seems like a really inefficient way of doing it.
Edit: I came up with this, but is there a better way?
def lucky(number):
f = 2
n = number * f
while True:
l = range(1, n + 1, 2)
i = 1
while i < len(l):
del l[l[i] - 1::l[i]]
i += 1
if len(l) >= number:
return l[number - 1]
f += 1
n = number * f
I came up with this, but is there a better way?
Truth is, there will always be a better way, the remaining question being: is it good enough for your need?
One possible improvement would be to turn all this into a generator function. That way, you would only compute new values as they are consumed. I came up with this version, which I only validated up to about 60 terms:
import itertools
def _idx_after_removal(removed_indices, value):
for removed in removed_indices:
value -= value / removed
return value
def _should_be_excluded(removed_indices, value):
for j in range(len(removed_indices) - 1):
value_idx = _idx_after_removal(removed_indices[:j + 1], value)
if value_idx % removed_indices[j + 1] == 0:
return True
return False
def lucky():
yield 1
removed_indices = [2]
for i in itertools.count(3, 2):
if not _should_be_excluded(removed_indices, i):
yield i
removed_indices.append(i)
removed_indices = list(set(removed_indices))
removed_indices.sort()
If you want to extract for example the 100th term from this generator, you can use itertools nth recipe:
def nth(iterable, n, default=None):
"Returns the nth item or a default value"
return next(itertools.islice(iterable, n, None), default)
print nth(lucky(), 100)
I hope this works, and there's without any doubt more room for code improvement (but as stated previously, there's always room for improvement!).
With numpy arrays, you can make use of boolean indexing, which may help. For example:
>>> a = numpy.arange(10)
>>> print a
[0 1 2 3 4 5 6 7 8 9]
>>> print a[a > 3]
[4 5 6 7 8 9]
>>> mask = np.array([True, False, True, False, True, False, True, False, True, False])
>>> print a[mask]
[0 2 4 6 8]
Here is a lucky number function using numpy arrays:
import numpy as np
class Didnt_Findit(Exception):
pass
def lucky(n):
'''Return the nth lucky number.
n --> int
returns int
'''
# initial seed
lucky_numbers = [1]
# how many numbers do you need to get to n?
candidates = np.arange(1, n*100, 2)
# use numpy array boolean indexing
next_lucky = candidates[candidates > lucky_numbers[-1]][0]
# accumulate lucky numbers till you have n of them
while next_lucky < candidates[-1]:
lucky_numbers.append(next_lucky)
#print lucky_numbers
if len(lucky_numbers) == n:
return lucky_numbers[-1]
mask_start = next_lucky - 1
mask_step = next_lucky
mask = np.array([True] * len(candidates))
mask[mask_start::mask_step] = False
#print mask
candidates = candidates[mask]
next_lucky = candidates[ candidates > lucky_numbers[-1]][0]
raise Didnt_Findit('n = ', n)
>>> print lucky(10)
33
>>> print lucky(50)
261
>>> print lucky(500)
3975
Checked mine and #icecrime's output for 10, 50 and 500 - they matched.
Yours is much faster than mine and scales better with n.
n=input('enter n ')
a= list(xrange(1,n))
x=a[1]
for i in range(1,n):
del a[x-1::x]
x=a[i]
l=len(a)
if i==l-1:
break
print "lucky numbers till %d" % n
print a
lets do this with an example.lets print lucky numbers till 100
put n=100
firstly a=1,2,3,4,5....100
x=a[1]=2
del a[1::2] leaves
a=1,3,5,7....99
now l=50
and now x=3
then del a[2::3] leaving a =1,3,7,9,13,15,.....
and loop continues till i==l-1

Permutation growing algorithm in Python and print strings

I've done this algorithm before, in school, but I've forgotten how to do it. Basically I want to return a result that are strings like 'a[0]', 'a[0].a[0]' ...
length = range(0,2) #length = 2
depth = range(0,3) #depth = 3
for i in length:
for k in depth:
… print each permutation
RESULT
a[0]
a[0].a[0]
a[0].a[1]
a[0].a[0].a[0]
a[0].a[0].a[1]
a[0].a[1].a[0]
a[0].a[1].a[1]
a[1]
a[1].a[0]
a[1].a[1]
a[1].a[0].a[0]
a[1].a[0].a[1]
a[1].a[1].a[0]
a[1].a[1].a[1]
Changing a bit the ordering of the output, so that it is the same on all levels:
def thing (length, depth, prefix = None):
if not depth: return
if not prefix: prefix = []
for l in range (length):
r = prefix + ['a[{}]'.format (l) ]
yield '.'.join (r)
for r in thing (length, depth - 1, r):
yield r
for x in thing (2, 3): print (x)
Output is:
a[0]
a[0].a[0]
a[0].a[0].a[0]
a[0].a[0].a[1]
a[0].a[1]
a[0].a[1].a[0]
a[0].a[1].a[1]
a[1]
a[1].a[0]
a[1].a[0].a[0]
a[1].a[0].a[1]
a[1].a[1]
a[1].a[1].a[0]
a[1].a[1].a[1]
An alternative approach; as Hyperboreus points out, the key is realizing that the ordering of the first-elements does not match that of the following elements; so I handle them separately.
from itertools import product
def item_fmt(i):
return "a[{}]".format(repr(i))
def make_result(*args):
return ".".join(item_fmt(arg) for arg in args)
def main():
items = [0, 1]
maxdepth = 3
for first in items: # in order by first-item
print(make_result(first)) # show first-item-only
for depth in range(1, maxdepth): # in order by depth
for combo in product(items, repeat=depth): # generate all combinations of given depth
print(make_result(first, *combo))
if __name__=="__main__":
main()
results in
a[0]
a[0].a[0]
a[0].a[1]
a[0].a[0].a[0]
a[0].a[0].a[1]
a[0].a[1].a[0]
a[0].a[1].a[1]
a[1]
a[1].a[0]
a[1].a[1]
a[1].a[0].a[0]
a[1].a[0].a[1]
a[1].a[1].a[0]
a[1].a[1].a[1]

looping through loops in python?

I'm trying to solve this problem on the easy section of coderbyte and the prompt is:
Have the function ArrayAdditionI(arr) take the array of numbers stored in arr and return the string true if any combination of numbers in the array can be added up to equal the largest number in the array, otherwise return the string false. For example: if arr contains [4, 6, 23, 10, 1, 3] the output should return true because 4 + 6 + 10 + 3 = 23. The array will not be empty, will not contain all the same elements, and may contain negative numbers.
Here's my solution.
def ArrayAddition(arr):
arr = sorted(arr, reverse=True)
large = arr.pop(0)
storage = 0
placeholder = 0
for r in range(len(arr)):
for n in arr:
if n + storage == large: return True
elif n + storage < large: storage += n
else: continue
storage = 0
if placeholder == 0: placeholder = arr.pop(0)
else: arr.append(placeholder); placeholder = arr.pop(0)
return False
print ArrayAddition([2,95,96,97,98,99,100])
I'm not even sure if this is correct, but it seems to cover all the numbers I plug in. I'm wondering if there is a better way to solve this through algorithm which I know nothing of. I'm thinking a for within a for within a for, etc loop would do the trick, but I don't know how to do that.
What I have in mind is accomplishing this with A+B, A+C, A+D ... A+B+C ... A+B+C+D+E
e.g)
for i in range(len(arr):
print "III: III{}III".format(i)
storage = []
for j in range(len(arr):
print "JJ: II({}),JJ({})".format(i,j)
for k in range(len(arr):
print "K: I{}, J{}, K{}".format(i,j,k)
I've searched all over and found the suggestion of itertool, but I'm wondering if there is a way to write this code up more raw.
Thanks.
A recursive solution:
def GetSum(n, arr):
if len(arr) == 0 and n != 0:
return False
return (n == 0 or
GetSum(n, arr[1:]) or
GetSum(n-arr[0], arr[1:]))
def ArrayAddition(arr):
arrs = sorted(arr)
return GetSum(arrs[-1], arrs[:-1])
print ArrayAddition([2,95,96,97,98,99,100])
The GetSum function returns False when the required sum is non-zero and there are no items in the array. Then it checks for 3 cases:
If the required sum, n, is zero then the goal is achieved.
If we can get the sum with the remaining items after the first item is removed, then the goal is achieved.
If we can get the required sum minus the first element of the list on the rest of the list the goal is achieved.
Your solution doesn't work.
>>> ArrayAddition([10, 11, 20, 21, 30, 31, 60])
False
The simple solution is to use itertools to iterate over all subsets of the input (that don't contain the largest number):
def subsetsum(l):
l = list(l)
target = max(l)
l.remove(l)
for subset_size in xrange(1+len(l)):
for subset in itertools.combinations(l, subset_size):
if sum(subset) == target:
return True
return False
If you want to avoid itertools, you'll need to generate subsets directly. That can be accomplished by counting in binary and using the set bits to determine which elements to pick:
def subsetsum(l):
l = list(l)
target = max(l)
l.remove(l)
for subset_index in xrange(2**len(l)):
subtotal = 0
for i, num in enumerate(l):
# If bit i is set in subset_index
if subset_index & (1 << i):
subtotal += num
if subtotal == target:
return True
return False
Update: I forgot that you want to check all possible combinations. Use this instead:
def ArrayAddition(l):
for length in range(2, len(l)):
for lst in itertools.combinations(l, length):
if sum(lst) in l:
print(lst, sum(lst))
return True
return False
One-liner solution:
>>> any(any(sum(lst) in l for lst in itertools.combinations(l, length)) for length in range(2, len(l)))
Hope this helps!
Generate all the sums of the powerset and test them against the max
def ArrayAddition(L):
return any(sum(k for j,k in enumerate(L) if 1<<j&i)==max(L) for i in range(1<<len(L)))
You could improve this by doing some preprocessing - find the max first and remove it from L
One more way to do it...
Code:
import itertools
def func(l):
m = max(l)
rem = [itertools.combinations([x for x in l if not x == m],i) for i in range(2,len(l)-1)]
print [item for i in rem for item in i if sum(item)==m ]
if __name__=='__main__':
func([1,2,3,4,5])
Output:
[(1, 4), (2, 3)]
Hope this helps.. :)
If I understood the question correctly, simply this should return what you want:
2*max(a)<=sum(a)

Proper Usage of list.append in Python

Like to know why method 1 is correct and method 2 is wrong.
Method1:
def remove_duplicates(x):
y = []
for n in x:
if n not in y:
y.append(n)
return y
Method 2:
def remove_duplicates(x):
y = []
for n in x:
if n not in y:
y = y.append(n)
return y
I don't understand why the second method returns the wrong answer?
The list.append method returns None. So y = y.append(n)
sets y to None.
If this happens on the very last iteration of the for-loop, then None is returned.
If it happens before the last iteration, then on the next time through the loop,
if n not in y
will raise a
TypeError: argument of type 'NoneType' is not iterable
Note: In most cases there are faster ways to remove duplicates than Method 1, but how to do it depends on if you wish to preserve order, if the items are orderable, and if the items in x are hashable.
def unique_hashable(seq):
# Not order preserving. Use this if the items in seq are hashable,
# and you don't care about preserving order.
return list(set(seq))
def unique_hashable_order_preserving(seq):
# http://www.peterbe.com/plog/uniqifiers-benchmark (Dave Kirby)
# Use this if the items in seq are hashable and you want to preserve the
# order in which unique items in seq appear.
seen = set()
return [x for x in seq if x not in seen and not seen.add(x)]
def unique_unhashable_orderable(seq):
# Author: Tim Peters
# http://code.activestate.com/recipes/52560-remove-duplicates-from-a-sequence/
# Use this if the items in seq are unhashable, but seq is sortable
# (i.e. orderable). Note the result does not preserve order because of
# the sort.
#
# We can't hash all the elements. Second fastest is to sort,
# which brings the equal elements together; then duplicates are
# easy to weed out in a single pass.
# NOTE: Python's list.sort() was designed to be efficient in the
# presence of many duplicate elements. This isn't true of all
# sort functions in all languages or libraries, so this approach
# is more effective in Python than it may be elsewhere.
try:
t = list(seq)
t.sort()
except TypeError:
del t
else:
last = t[0]
lasti = i = 1
while i < len(seq):
if t[i] != last:
t[lasti] = last = t[i]
lasti += 1
i += 1
return t[:lasti]
def unique_unhashable_nonorderable(seq):
# Use this (your Method1) if the items in seq are unhashable and unorderable.
# This method is order preserving.
u = []
for x in seq:
if x not in u:
u.append(x)
return u
And this may be the fastest if you have NumPy and the items in seq are orderable:
import numpy as np
def unique_order_preserving_numpy(seq):
u, ind = np.unique(seq, return_index=True)
return u[np.argsort(ind)]

counting odd numbers in a list python

This is a part of my homework assignment and im close to the final answer but not quite yet. I need to write a function that counts odd numbers in a list.
Create a recursive function count_odd(l) which takes as its only argument a list of integers. The function will return a count of the number of list elements that are odd, i.e., not evenly divisible by 2.\
>>> print count_odd([])
0
>>> print count_odd([1, 3, 5])
3
>>> print count_odd([2, 4, 6])
0
>>> print count_odd([0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144])
8
Here is what i have so far:
#- recursive function count_odd -#
def count_odd(l):
"""returns a count of the odd integers in l.
PRE: l is a list of integers.
POST: l is unchanged."""
count_odd=0
while count_odd<len(l):
if l[count_odd]%2==0:
count_odd=count_odd
else:
l[count_odd]%2!=0
count_odd=count_odd+1
return count_odd
#- test harness
print count_odd([])
print count_odd([1, 3, 5])
print count_odd([2, 4, 6])
print count_odd([0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144])
Can u help explain what im missing. The first two test harness works fine but i cant get the final two. Thanks!
Since this is homework, consider this pseudo-code that just counts a list:
function count (LIST)
if LIST has more items
// recursive case.
// Add one for the current item we are counting,
// and call count() again to process the *remaining* items.
remaining = everything in LIST except the first item
return 1 + count(remaining)
else
// base case -- what "ends" the recursion
// If an item is removed each time, the list will eventually be empty.
return 0
This is very similar to what the homework is asking for, but it needs to be translate to Python and you must work out the correct recursive case logic.
Happy coding.
def count_odd(L):
return (L[0]%2) + count_odd(L[1:]) if L else 0
Are slices ok? Doesn't feel recursive to me, but I guess the whole thing is kind of against usual idioms (i.e. - recursion of this sort in Python):
def countOdd(l):
if l == list(): return 0 # base case, empty list means we're done
return l[0] % 2 + countOdd(l[1:]) # add 1 (or don't) depending on odd/even of element 0. recurse on the rest
x%2 is 1 for odds, 0 for evens. If you are uncomfortable with it or just don't understand it, use the following in place of the last line above:
thisElement = l[0]
restOfList = l[1:]
if thisElement % 2 == 0: currentElementOdd = 0
else: currentElementOdd = 1
return currentElementOdd + countOdd(restOfList)
PS - this is pretty recursive, see what your teacher says if you turn this in =P
>>> def countOdd(l):
... return fold(lambda x,y: x+(y&1),l,0)
...
>>> def fold(f,l,a):
... if l == list(): return a
... return fold(f,l[1:],f(a,l[0]))
All of the prior answers are subdividing the problem into subproblems of size 1 and size n-1. Several people noted that the recursive stack might easily blow out. This solution should keep the recursive stack size at O(log n):
def count_odd(series):
l = len(series) >> 1
if l < 1:
return series[0] & 1 if series else 0
else:
return count_odd(series[:l]) + count_odd(series[l:])
The goal of recursion is to divide the problem into smaller pieces, and apply the solution to the smaller pieces. In this case, we can check if the first number of the list (l[0]) is odd, then call the function again (this is the "recursion") with the rest of the list (l[1:]), adding our current result to the result of the recursion.
def count_odd(series):
if not series:
return 0
else:
left, right = series[0], series[1:]
return count_odd(right) + (1 if (left & 1) else 0)
Tail recursion
def count_odd(integers):
def iter_(lst, count):
return iter_(rest(lst), count + is_odd(first(lst))) if lst else count
return iter_(integers, 0)
def is_odd(integer):
"""Whether the `integer` is odd."""
return integer % 2 != 0 # or `return integer & 1`
def first(lst):
"""Get the first element from the `lst` list.
Return `None` if there are no elements.
"""
return lst[0] if lst else None
def rest(lst):
"""Return `lst` list without the first element."""
return lst[1:]
There is no tail-call optimization in Python, so the above version is purely educational.
The call could be visualize as:
count_odd([1,2,3]) # returns
iter_([1,2,3], 0) # could be replaced by; depth=1
iter_([2,3], 0 + is_odd(1)) if [1,2,3] else 0 # `bool([1,2,3])` is True in Python
iter_([2,3], 0 + True) # `True == 1` in Python
iter_([2,3], 1) # depth=2
iter_([3], 1 + is_odd(2)) if [2,3] else 1
iter_([3], 1 + False) # `False == 0` in Python
iter_([3], 1) # depth=3
iter_([], 1 + is_odd(3)) if [3] else 1
iter_([], 2) # depth=4
iter_(rest([]), 2 + is_odd(first([])) if [] else 2 # bool([]) is False in Python
2 # the answer
Simple trampolining
To avoid 'max recursion depth exceeded' errors for large arrays all tail calls in recursive functions can be wrapped in lambda: expressions; and special trampoline() function can be used to unwrap such expressions. It effectively converts recursion into iterating over a simple loop:
import functools
def trampoline(function):
"""Resolve delayed calls."""
#functools.wraps(function)
def wrapper(*args):
f = function(*args)
while callable(f):
f = f()
return f
return wrapper
def iter_(lst, count):
#NOTE: added `lambda:` before the tail call
return (lambda:iter_(rest(lst), count+is_odd(first(lst)))) if lst else count
#trampoline
def count_odd(integers):
return iter_(integers, 0)
Example:
count_odd([1,2,3])
iter_([1,2,3], 0) # returns callable
lambda:iter_(rest(lst), count+is_odd(first(lst))) # f = f()
iter_([2,3], 0+is_odd(1)) # returns callable
lambda:iter_(rest(lst), count+is_odd(first(lst))) # f = f()
iter_([3], 1+is_odd(2)) # returns callable
lambda:iter_(rest(lst), count+is_odd(first(lst))) # f = f()
iter_([], 1+is_odd(3))
2 # callable(2) is False
I would write it like this:
def countOddNumbers(numbers):
sum = 0
for num in numbers:
if num%2!=0:
sum += numbers.count(num)
return sum
not sure if i got your question , but as above something similar:
def countOddNumbers(numbers):
count=0
for i in numbers:
if i%2!=0:
count+=1
return count
Generator can give quick result in one line code:
sum((x%2 for x in nums))

Categories

Resources