Related
Suppose I have an input integer 12345. How can I split it into a list like [1, 2, 3, 4, 5]?
Convert the number to a string so you can iterate over it, then convert each digit (character) back to an int inside a list-comprehension:
>>> [int(i) for i in str(12345)]
[1, 2, 3, 4, 5]
return array as string
>>> list(str(12345))
['1', '2', '3', '4', '5']
return array as integer
>>> map(int,str(12345))
[1, 2, 3, 4, 5]
I'd rather not turn an integer into a string, so here's the function I use for this:
def digitize(n, base=10):
if n == 0:
yield 0
while n:
n, d = divmod(n, base)
yield d
Examples:
tuple(digitize(123456789)) == (9, 8, 7, 6, 5, 4, 3, 2, 1)
tuple(digitize(0b1101110, 2)) == (0, 1, 1, 1, 0, 1, 1)
tuple(digitize(0x123456789ABCDEF, 16)) == (15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
As you can see, this will yield digits from right to left. If you'd like the digits from left to right, you'll need to create a sequence out of it, then reverse it:
reversed(tuple(digitize(x)))
You can also use this function for base conversion as you split the integer. The following example splits a hexadecimal number into binary nibbles as tuples:
import itertools as it
tuple(it.zip_longest(*[digitize(0x123456789ABCDEF, 2)]*4, fillvalue=0)) == ((1, 1, 1, 1), (0, 1, 1, 1), (1, 0, 1, 1), (0, 0, 1, 1), (1, 1, 0, 1), (0, 1, 0, 1), (1, 0, 0, 1), (0, 0, 0, 1), (1, 1, 1, 0), (0, 1, 1, 0), (1, 0, 1, 0), (0, 0, 1, 0), (1, 1, 0, 0), (0, 1, 0, 0), (1, 0, 0, 0))
Note that this method doesn't handle decimals, but could be adapted to.
[int(i) for i in str(number)]
or, if do not want to use a list comprehension or you want to use a base different from 10
from __future__ import division # for compatibility of // between Python 2 and 3
def digits(number, base=10):
assert number >= 0
if number == 0:
return [0]
l = []
while number > 0:
l.append(number % base)
number = number // base
return l
While list(map(int, str(x))) is the Pythonic approach, you can formulate logic to derive digits without any type conversion:
from math import log10
def digitize(x):
n = int(log10(x))
for i in range(n, -1, -1):
factor = 10**i
k = x // factor
yield k
x -= k * factor
res = list(digitize(5243))
[5, 2, 4, 3]
One benefit of a generator is you can feed seamlessly to set, tuple, next, etc, without any additional logic.
like #nd says but using the built-in function of int to convert to a different base
>>> [ int(i,16) for i in '0123456789ABCDEF' ]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
>>> [int(i,2) for i in "100 010 110 111".split()]
[4, 2, 6, 7]
Another solution that does not involve converting to/from strings:
from math import log10
def decompose(n):
if n == 0:
return [0]
b = int(log10(n)) + 1
return [(n // (10 ** i)) % 10 for i in reversed(range(b))]
Using join and split methods of strings:
>>> a=12345
>>> list(map(int,' '.join(str(a)).split()))
[1, 2, 3, 4, 5]
>>> [int(i) for i in ' '.join(str(a)).split()]
[1, 2, 3, 4, 5]
>>>
Here we also use map or a list comprehension to get a list.
Strings are just as iterable as arrays, so just convert it to string:
str(12345)
Simply turn it into a string, split, and turn it back into an array integer:
nums = []
c = 12345
for i in str(c):
l = i.split()[0]
nums.append(l)
np.array(nums)
I have the following two lists:
numlist = [1, 1, 1, 1, 4, 1, 1, 4, 1, 2]
lenwords = [2,3,5]
I want to see the number at each index in len words as such:
for number in range(len(lenwords)):
print(lenwords[number])
And then take that number of items in numlist suggested by each index in lenwords (2,3,5) and add them together, like so:
add 1+1 then 1+1+4 then 1+1+4+1+2
I'm thinking that I could use itertools, but not sure how to do so.
I make an iterable out of numlist, then iterate over lenwords, using itertools.islice to pull out the count you want from the numlist generator.
https://docs.python.org/3/library/itertools.html#itertools.islice
import itertools
def sumlengths(numlist, lenwords):
numbers = iter(numlist)
for length in lenwords:
yield sum(itertools.islice(numbers, length))
numlist = [1, 1, 1, 1, 4, 1, 1, 4, 1, 2]
lenwords = [2,3,5]
print (*sumlengths(numlist, lenwords))
2 6 9
I did not validate the length of the inputs.
Another approach:
numlist = [1, 1, 1, 1, 4, 1, 1, 4, 1, 2]
lenwords = [2,3,5]
gen = iter(numlist)
result = []
for n in lenwords:
total = 0
for _ in range(n):
total += next(gen)
result.append(total)
The resulting list total is [2, 6, 9], as desired.
with out using ittertools:
numlist = [1, 1, 1, 1, 4, 1, 1, 4, 1, 2]
lenwords = [2, 3, 5]
counter = 0
for number in lenwords:
q = numlist[counter:counter+number]
print(sum(q))
counter += number
output
2
6
9
I'm trying some python and I got this:
I have a string S='3,0,4,0,3,1,0,1,0,1,0,0,5,0,4,2' and m=9.
I want to know how many substrings with with sum equals m there are.
So with S and m above i whould get 7 as a result as:
'3,0,4,0,3,1,0,1,0,1,0,0,5,0,4,2'
_'0,4,0,3,1,0,1,0'_____________
_'0,4,0,3,1,0,1'_______________
___'4,0,3,1,0,1,0'_____________
____'4,0,3,1,0,1'_______________
____________________'0,0,5,0,4'_
______________________'0,5,0,4'_
_______________________'5,0,4'_
Now, the code i came up with does something like that
def es1(S,m):
c = 0
M = 0
ls = StringToInt(S)
for x in ls:
i= ls.index(x)
for y in ls[i+1:]:
M = x + y
if M == m:
c += 1
M = 0
break
if M > m:
M = 0
break
else:
continue
return c
def StringToInt(ls):
s = [int(x) for x in ls.split(',')]
return s
Where StringToInt obv gives me a list of int to work with.
The thing I don't get is where my concept is wrong since es1 returns 3
You could use zip to progressively add numbers to a list of sums and count how many 9s you have at each pass:
S = '3,0,4,0,3,1,0,1,0,1,0,0,5,0,4,2'
m = 9
numbers = list(map(int,S.split(",")))
result = 0
sums = numbers
for i in range(len(numbers)):
result += sums.count(m)
sums = [a+b for a,b in zip(sums,numbers[i+1:]) ]
print(result)
For a more "functional programming" approach, you can use accumulate from itertools:
from itertools import accumulate
numbers = list(map(int,S.split(",")))
ranges = (numbers[i:] for i in range(len(numbers)))
sums = (accumulate(r) for r in ranges)
result = sum( list(s).count(m) for s in sums )
print(result)
To explain how this works, let's first look at the content of ranges, which are substrings from each position up to the end of the list:
[3, 0, 4, 0, 3, 1, 0, 1, 0, 1, 0, 0, 5, 0, 4, 2]
[0, 4, 0, 3, 1, 0, 1, 0, 1, 0, 0, 5, 0, 4, 2]
[4, 0, 3, 1, 0, 1, 0, 1, 0, 0, 5, 0, 4, 2]
[0, 3, 1, 0, 1, 0, 1, 0, 0, 5, 0, 4, 2]
[3, 1, 0, 1, 0, 1, 0, 0, 5, 0, 4, 2]
[1, 0, 1, 0, 1, 0, 0, 5, 0, 4, 2]
[0, 1, 0, 1, 0, 0, 5, 0, 4, 2]
[1, 0, 1, 0, 0, 5, 0, 4, 2]
[0, 1, 0, 0, 5, 0, 4, 2]
[1, 0, 0, 5, 0, 4, 2]
[0, 0, 5, 0, 4, 2]
[0, 5, 0, 4, 2]
[5, 0, 4, 2]
[0, 4, 2]
[4, 2]
[2]
When we make a cumulative sum of the rows (sums), we obtain the total of values starting at the position defined by the row number and for a length defined by the column number. e.g. line 5, column 3 represents the sum of 3 values starting at the fifth position:
[3, 3, 7, 7, 10, 11, 11, 12, 12, 13, 13, 13, 18, 18, 22, 24]
[0, 4, 4, 7, 8, 8, 9, 9, 10, 10, 10, 15, 15, 19, 21]
[4, 4, 7, 8, 8, 9, 9, 10, 10, 10, 15, 15, 19, 21]
[0, 3, 4, 4, 5, 5, 6, 6, 6, 11, 11, 15, 17]
[3, 4, 4, 5, 5, 6, 6, 6, 11, 11, 15, 17]
[1, 1, 2, 2, 3, 3, 3, 8, 8, 12, 14]
[0, 1, 1, 2, 2, 2, 7, 7, 11, 13]
[1, 1, 2, 2, 2, 7, 7, 11, 13]
[0, 1, 1, 1, 6, 6, 10, 12]
[1, 1, 1, 6, 6, 10, 12]
[0, 0, 5, 5, 9, 11]
[0, 5, 5, 9, 11]
[5, 5, 9, 11]
[0, 4, 6]
[4, 6]
[2]
In this triangular matrix each position corresponds to the sum of one of the possible substrings. We simply need to count the number of 9s in there to get the result.
The above solutions will perform in O(N^2) time but, if you are concerned with performance, there is a way to obtain the result in O(N) time using a dictionary. Rather than build the whole sub arrays in the above logic, you could simply count the number of positions that add up to each sum. Then, for the sum at each position, go directly to a previous sum total that is exactly m less to get the number of substrings for that position.
from itertools import accumulate
from collections import Counter
numbers = map(int,S.split(","))
result = 0
sums = Counter([0])
for s in accumulate(numbers):
result += sums[s-m]
sums[s] += 1
print(result)
Note that all these solutions support negative numbers in the list as well as a negative or zero target.
As mentioned by others, your code only looks at sums of pairs of elements from the list. You need to look at sublists.
Here is a O(n) complexity solution (i.e. it's efficient since it only scans though the list once):
def es2(s, m):
s = string_to_int(s)
c = 0
# index of left of sub-list
left = 0
# index of right of sub-list
right = 0
# running total of sublist sum
current_sum = 0
while True:
# if the sub-list has the correct sum
if current_sum == m:
# add as many zeros on the end as works
temp_current_sum = current_sum
for temp_right in range(right, len(s) + 1):
if temp_current_sum == m:
c += 1
if temp_right<len(s):
temp_current_sum += s[temp_right]
else:
break
if current_sum >= m:
# move the left end along and update running total
current_sum -= s[left]
left += 1
else:
# move the right end along and update running total
if right == len(s):
# if the end of the list is reached, exit
return c
current_sum += s[right]
right += 1
def string_to_int(ls):
s = [int(x) for x in ls.split(',')]
return s
if __name__ == '__main__':
print(es2('3,0,4,0,3,1,0,1,0,1,0,0,5,0,4,2', 9))
This is the code you are looking for man. i felt looking by position was better for this problem so I did it and it worked.
def es1(S,m):
c = 0
M = 0
ls = StringToInt(S)
for i in range(0, len(ls)):
M = 0
for x in range(i, len(ls)):
M += ls[x]
if M == m:
c += 1
elif M >= m:
break
return c
def StringToInt(ls):
s = [int(x) for x in ls.split(',')]
return s
print(es1("3,0,4,0,3,1,0,1,0,1,0,0,5,0,4,2", 9))
OUTPUT:
7
Your code counts how many pairs of numbers there are in the String S which together give m while you actually want to test all possible substrings.
You could do something like:
numbers = [3,0,4,0,3,1,0,1,0,1,0,0,5,0,4,2]
m = 9
c = 0
for i in range(len(numbers)):
for j in range(len(numbers)-i):
sum = 0
for k in numbers[i:i+j]:
sum += k
if sum == m:
c += 1
print(c)
Output:
7
EDIT! ->This Code is actually all possible subsets, not sublists. I am going to leave this here though in case this solution is helpful to anyone who visits this question.
This code gets every solution. If you take a look in the function es1() the result variable is huge list of arrays with all the possible solutions.
import itertools
def es1(S,m):
result = [seq for i in range(len(StringToInt(S)), 0, -1) for seq in itertools.combinations(StringToInt(S), i) if sum(seq) == m]
return len(result)
def StringToInt(ls):
s = [int(x) for x in ls.split(',')]
return s
print(es1("3,0,4,0,3,1,0,1,0,1,0,0,5,0,4,2", 9))
OUTPUT:
4608
There are 4608 possible sets that add to the value 9.
s = "3,0,4,0,3,1,0,1,0,1,0,0,5,0,4,2"
m = 9
sn = s.replace(",","+") # replace "," with "+"
d = {} # create a dictionary
# create list of strings:
# s2 = ["3+0","0+4","4+0".............]
# s3 = ["3+0+4","0+4+0","4+0+3".............]
# .
# .
# .
for n in range(2,len(s.split(","))):
d["s%s"%n] = [sn[i:i+(2*n-1)] for i in range(0,len(sn),2)][:-n+1]
# evaluate whether sum of individual lists equal to m or not, then find out how many such lists are there
l = sum([eval(x)==m for y in d.values() for x in y] )
# remember we didnot add s1, i,e check whether individual string == m or not
l = l+sum([x==m for x in s.split(",")])
print(l)
7
I want to check if, for example, the digit '2' is in 4059304593.
My aim is to then check if there are any of the digits 1-9 not in my integer. This is what I have tried:
for i in xrange(10):
for j in xrange(100):
num = str(i^j)
one_count = 0
two_count = 0
for k in xrange(len(num)):
if num[k] == 1:
one_count += 1
if num[k] == 2:
two_count += 1
Then my "counts" would go all the way down to nine_count, and if any of the counts are 0, then that digit isn't in 'num'. From what I've read on these sites, my script would be inefficient - can someone point out a better way?
This "digit" thing calls for a string approach, not a numeric one (reminds me of some Project Euler puzzles).
I'd create a set out of the digits of your number first (removing duplicates at the same time)
s = set(str(4059304593))
then to check for a digit:
print('2' in s)
(note that in for a set is performant)
then, to check whether s contains all the 013456789 digits:
print(s.issuperset("013456789"))
(if this must be done multiple times, it may be worth to create a set with the string, issuperset will work faster)
You could convert your number to a string, then to a set to get the unique digits.
You just have to iterate over digits in 0-9 to find the ones not present in your original number :
>>> set(map(int,str(4059304593)))
set([0, 9, 3, 4, 5])
>>> digits = _
>>> [i for i in range(10) if i not in digits]
[1, 2, 6, 7, 8]
L = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
j = 0
nL = [0, 0, 0, 0, 0, 0, 0, 0, 0]
n = 1004 #number
while n:
i = n%10
nL[i] = 1
n //= 10
OUT
nL = [1, 1, 0, 0, 1, 0, 0, 0, 0, 0]
Explanation:
if nL[i] is 1, then the i-th digit is in n
Since you just want to find out which digits aren't in your number:
def not_in_number(n):
return {*range(10)} - {*map(int, {*str(n)})}
Usage:
>>> not_in_number(4059304593)
{1, 2, 6, 7, 8}
This takes the set of digits ({*range(10)}) and substracts from it the set of digits of your number ({*map(int, {*str(n)})}), created by mapping the set of digit characters to integers. If you find the {*...} notation confusing, you can always use set(...) instead, which will also work for Python 2.7+:
def not_in_number(n):
return set(range(10)) - set(map(int, set(str(n))))
Another way is using - with sets:
set('0123456789') - set(str(4059304593))
Result are all digits that aren't in your integer:
{'2', '7', '1', '6', '8'}
I have a sequence like [0, 1, 0, 1, 0, 1, 0] and I need a function to remove repeated adjacent sequence pairs, keeping the first one, and return [0, 1, 0]. These are some results I expect.
>>> remove_repeated_pairs([0, 1])
[0, 1]
>>> remove_repeated_pairs([0, 1, 0])
[0, 1, 0]
>>> remove_repeated_pairs([0, 1, 0, 1])
[0, 1]
>>> remove_repeated_pairs([0, 1, 0, 1, 0])
[0, 1, 0]
>>> remove_repeated_pairs([2, 0, 1, 0, 1, 0])
[2, 0, 1, 0]
>>> remove_repeated_pairs([1, 2, 0, 1, 0, 1, 0])
[1, 2, 0, 1, 0]
first edition:
I tried this code:
def remove_repeated_pairs(seq):
result = []
for i in range(0, len(seq), 2):
if len(result) >= 2:
last_seq = result[-2:]
else:
last_seq = None
pair = seq[i:i + 2]
if pair != last_seq:
result.extend(pair)
return result
But it doesn't works with this:
>>> remove_repeated_pairs([1, 3, 0, 2, 1, 2, 1, 3, 0])
[1, 3, 0, 2, 1, 2, 1, 3, 0]
The right answer should be [1, 3, 0, 2, 1, 3, 0]
I think that the issue comes from the fact that you go over the elements of your list 2 by 2 (for i in range(0, len(seq), 2).
So if a repeated pair starts on an odd place, you won't detect it - as in the last example you give.
I would try something like:
def remove_repeated_pairs(l):
i = 2;
while i < len(l)-1:
if l[i] == l[i-2] and l[i+1]==l[i-1]:
l.pop(i);
l.pop(i);
else:
i+=1;
return l;
Regards,
Here's version that works with an arbitrary iterable, not just sequences:
def remove_repeated_pairs(iterable):
it = iter(iterable)
a = next(it) # always yield the first pair
yield a
b = next(it)
yield b
c = next(it)
for d in it:
if a != c or b != d:
yield c
a, b, c = b, c, d # shift by one item
else: # repeated pair, skip it
a, b, c = c, d, next(it)
yield c
Example
>>> list(remove_repeated_pairs([1, 3, 0, 2, 1, 2, 1, 3, 0]))
[1, 3, 0, 2, 1, 3, 0]
Here is a more concise version:
def remove_repeated_pairs(seq):
pairs = zip([-1] + seq,seq)[1:]
l = [index for (index,pair) in enumerate(pairs) if (index > 1) and
(pair == pairs[index-2])]
return [seq[x] for x in range(len(seq)) if x not in l and x+1 not in l ]
print remove_repeated_pairs([1, 3, 0, 2, 1, 2, 1, 3, 0])
#OUTPUT: [1, 3, 0, 2, 1, 3, 0]
print remove_repeated_pairs([1, 2, 4, 1, 4, 1, 3])
#OUTPUT: [1, 2, 4, 1, 3]
You have to check pairs starting at odd indices as well, i.e. pairs seq[1:2] equals seq[3:4] as well as even ones, i.e. seq[0:1] equals seq[2:3]
def remove_repeated_pairs(seq):
ret = [seq[0]]
s = None
i = 1
while i < len(seq)-1:
pair = (seq[i], seq[i+1])
if pair != s:
s = (seq[i-1], seq[i])
ret.append(seq[i])
else:
i+=1
i+=1
if i == len(seq)-1:
ret.append(seq[i])
return ret
You need to move forward one by one instead of two by two
def remove_repeated_pairs(l):
if(len(l) < 4):
return l
result = l[:2]
i = 2
while i < (len(l)-1):
if l[i] == result[-2] and l[i+1] == result[-1]:
i += 2
else:
result.append(l[i])
i += 1
result += l[i:]
return result