How to enumerate a range of numbers starting at 1 - python

I am using Python 2.5, I want an enumeration like so (starting at 1 instead of 0):
[(1, 2000), (2, 2001), (3, 2002), (4, 2003), (5, 2004)]
I know in Python 2.6 you can do: h = enumerate(range(2000, 2005), 1) to give the above result but in python2.5 you cannot...
Using Python 2.5:
>>> h = enumerate(range(2000, 2005))
>>> [x for x in h]
[(0, 2000), (1, 2001), (2, 2002), (3, 2003), (4, 2004)]
Does anyone know a way to get that desired result in Python 2.5?

As you already mentioned, this is straightforward to do in Python 2.6 or newer:
enumerate(range(2000, 2005), 1)
Python 2.5 and older do not support the start parameter so instead you could create two range objects and zip them:
r = xrange(2000, 2005)
r2 = xrange(1, len(r) + 1)
h = zip(r2, r)
print h
Result:
[(1, 2000), (2, 2001), (3, 2002), (4, 2003), (5, 2004)]
If you want to create a generator instead of a list then you can use izip instead.

Just to put this here for posterity sake, in 2.6 the "start" parameter was added to enumerate like so:
enumerate(sequence, start=1)

Python 3
Official Python documentation: enumerate(iterable, start=0)
You don't need to write your own generator as other answers here suggest. The built-in Python standard library already contains a function that does exactly what you want:
>>> seasons = ['Spring', 'Summer', 'Fall', 'Winter']
>>> list(enumerate(seasons))
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]
>>> list(enumerate(seasons, start=1))
[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]
The built-in function is equivalent to this:
def enumerate(sequence, start=0):
n = start
for elem in sequence:
yield n, elem
n += 1

Easy, just define your own function that does what you want:
def enum(seq, start=0):
for i, x in enumerate(seq):
yield i+start, x

Simplest way to do in Python 2.5 exactly what you ask about:
import itertools as it
... it.izip(it.count(1), xrange(2000, 2005)) ...
If you want a list, as you appear to, use zip in lieu of it.izip.
(BTW, as a general rule, the best way to make a list out of a generator or any other iterable X is not [x for x in X], but rather list(X)).

from itertools import count, izip
def enumerate(L, n=0):
return izip( count(n), L)
# if 2.5 has no count
def count(n=0):
while True:
yield n
n+=1
Now h = list(enumerate(xrange(2000, 2005), 1)) works.

enumerate is trivial, and so is re-implementing it to accept a start:
def enumerate(iterable, start = 0):
n = start
for i in iterable:
yield n, i
n += 1
Note that this doesn't break code using enumerate without start argument. Alternatively, this oneliner may be more elegant and possibly faster, but breaks other uses of enumerate:
enumerate = ((index+1, item) for index, item)
The latter was pure nonsense. #Duncan got the wrapper right.

>>> list(enumerate(range(1999, 2005)))[1:]
[(1, 2000), (2, 2001), (3, 2002), (4, 2003), (5, 2004)]

h = [(i + 1, x) for i, x in enumerate(xrange(2000, 2005))]

Ok, I feel a bit stupid here... what's the reason not to just do it with something like
[(a+1,b) for (a,b) in enumerate(r)] ? If you won't function, no problem either:
>>> r = range(2000, 2005)
>>> [(a+1,b) for (a,b) in enumerate(r)]
[(1, 2000), (2, 2001), (3, 2002), (4, 2003), (5, 2004)]
>>> enumerate1 = lambda r:((a+1,b) for (a,b) in enumerate(r))
>>> list(enumerate1(range(2000,2005))) # note - generator just like original enumerate()
[(1, 2000), (2, 2001), (3, 2002), (4, 2003), (5, 2004)]

>>> h = enumerate(range(2000, 2005))
>>> [(tup[0]+1, tup[1]) for tup in h]
[(1, 2000), (2, 2001), (3, 2002), (4, 2003), (5, 2004)]
Since this is somewhat verbose, I'd recommend writing your own function to generalize it:
def enumerate_at(xs, start):
return ((tup[0]+start, tup[1]) for tup in enumerate(xs))

I don't know how these posts could possibly be made more complicated then the following:
# Just pass the start argument to enumerate ...
for i,word in enumerate(allWords, 1):
word2idx[word]=i
idx2word[i]=word

Related

python 2.7 unique calculation issue

Using Python 2.7, I have a list, and each element in the list is a (sub-list) -- a list of tuples. I want to remove the duplicate sub-list, I post input and expected output. I tried to use set, but there is error said list is not hashable. Anyone have good elegant code solutions? Thanks.
a=[[(1,2),(1,3)],
[(1,3),(1,2)],
[(1,2),(1,3)]]
# expect output
'''
a=[[(1,2),(1,3)],
[(1,3),(1,2)]]
'''
Try this! This is the simplest method.
a = [[(1,2),(1,3)],
[(1,3),(1,2)],
[(1,2),(1,3)]]
print [list(i) for i in set(map(tuple, a))]
[[(1, 3), (1, 2)], [(1, 2), (1, 3)]] //output
The above one is without any library support and also the ordering of the original list can't be ensured.
If you want to preserve the order of the list, then go for collections library.
from collections import OrderedDict
a = [[(1,2),(1,3)],
[(1,3),(1,2)],
[(1,2),(1,3)]]
print map(list, OrderedDict.fromkeys(map(tuple, a)))
[[(1, 2), (1, 3)], [(1, 3), (1, 2)]] //output
I think you can use a set, something like below
a=[[(1,2),(1,3)],
[(1,3),(1,2)],
[(1,2),(1,3)]]
unique_list = [list(x) for x in set(tuple(x) for x in a)]
print unique_list
Output:
[[(1, 3), (1, 2)], [(1, 2), (1, 3)]]
See working repl here - https://repl.it/EinE/1

How do I organise a nested list representing coordinate-values to a coordinate-list

I would like to change my data-structure that get from my data-files in such a way that I get a list of all coordinate-values for every coordinates (so a list for all coordinates filled with values)
e.g.
for i in range (files):
open file
file_output = [[0,4,6],[9,4,1],[2,5,3]]
second loop
file_output = [[6,1,8],[4,7,3],[3,7,0]]
to
coordinates = [[0,6],[4,1],[6,8],[9,4],[4,7],[1,3],[2,3],[5,7],[3,0]]
It should be noted that I use over 1000 files of this format, which I should merge.
You could also explore the built-in zip() function
>>> l = []
>>> for k,v in zip(a,b):
l.append(zip(k,v))
>>> print l
[[0,6],[4,1],[6,8],[9,4],[4,7],[1,3],[2,3],[5,7],[3,0]]
>>> a = [[0,4,6],[9,4,1],[2,5,3]]
>>> b = [[6,1,8],[4,7,3],[3,7,0]]
>>> from itertools import chain
>>> zip(chain(*a),chain(*b))
[(0, 6), (4, 1), (6, 8), (9, 4), (4, 7), (1, 3), (2, 3), (5, 7), (3, 0)]
>>>
This should be useful.
[zip(i,j) for i in a for j in b]
However it provides list of tuples, which should satisfy your needs.
If there will only be two lists, you can use this as well.
[[i, j] for i in a for j in b]

Is it possible to include mutiple equations in a lambda function

I'm trying to include multiple operations in the lambda function with variables that have different lengths, i.e. something like:
$ serial_result = map(lambda x,y:(x**2,y**3), range(20), range(10))
but this doesn't work. Could someone tell me how to get around this?
I understand that:
$ serial_result = map(lambda x,y:(x**2,y**3), range(0,20,2), range(10))
works because the arrays of "x" and "y" have the same length.
If you want the product of range items you can use itertools.product :
>>> from itertools import product
>>> serial_result = map(lambda x:(x[0]**2,x[1]**3), product(range(20), range(10)))
If you want to pass the pairs to lambda like second case you can use itertools.zip_longest (in python 2 use izip_longest)and pass a fillvalue to fill the missed items,
>>> from itertools import zip_longest
>>> serial_result = map(lambda x:(x[0]**2,x[1]**3), zip_longest(range(20), range(10),fillvalue=1))
Note that if you are in python 2 you can pass multiple argument to lambda as a tuple :
>>> serial_result = map(lambda (x,y):(x**2,y**3), product(range(20), range(10)))
See the difference of izip_longest and product in following example :
>>> list(product(range(5),range(3)))
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2), (3, 0), (3, 1), (3, 2), (4, 0), (4, 1), (4, 2)]
>>> list(zip_longest(range(5),range(3)))
[(0, 0), (1, 1), (2, 2), (3, None), (4, None)]
>>> list(zip_longest(range(5),range(3),fillvalue=1))
[(0, 0), (1, 1), (2, 2), (3, 1), (4, 1)]
It sounds like you may be confused as to how exactly you want to use all the values in these two variables. There are several ways combine them...
If you want a result for every combination of an element in a and an element in b: itertools.product(a, b).
If you want to stop once you get to the end of the shorter: zip(a, b)
If you want to continue on until you've used all of the longest: itertools.zip_longer(a, b) (izip_longer in python 2). Once a runs out of elements it will be filled in with None, or a default you provide.

Accumulate items in a list of tuples

I have a list of tuples that looks like this:
lst = [(0, 0), (2, 3), (4, 3), (5, 1)]
What is the best way to accumulate the sum of the first and secound tuple elements? Using the example above, I'm looking for the best way to produce this list:
new_lst = [(0, 0), (2, 3), (6, 6), (11, 7)]
I am looking for a solution in Python 2.6
I would argue the best solution is itertools.accumulate() to accumulate the values, and using zip() to split up your columns and merge them back. This means the generator just handles a single column, and makes the method entirely scalable.
>>> from itertools import accumulate
>>> lst = [(0, 0), (2, 3), (4, 3), (5, 1)]
>>> list(zip(*map(accumulate, zip(*lst))))
[(0, 0), (2, 3), (6, 6), (11, 7)]
We use zip() to take the columns, then apply itertools.accumulate() to each column, then use zip() to merge them back into the original format.
This method will work for any iterable, not just sequences, and should be relatively efficient.
Prior to 3.2, accumulate can be defined as:
def accumulate(iterator):
total = 0
for item in iterator:
total += item
yield total
(The docs page gives a more generic implementation, but for this use case, we can use this simple implementation).
How about this generator:
def accumulate_tuples(iterable):
accum_a = accum_b = 0
for a, b in iterable:
accum_a += a
accum_b += b
yield accum_a, accum_b
If you need a list, just call list(accumulate_tuples(your_list)).
Here's a version that works for arbitrary length tuples:
def accumulate_tuples(iterable):
it = iter(iterable):
accum = next(it) # initialize with the first value
yield accum
for val in it: # iterate over the rest of the values
accum = tuple(a+b for a, b in zip(accum, val))
yield accum
>> reduce(lambda x,y: (x[0] + y[0], x[1] + y[1]), lst)
(11, 7)
EDIT. I can see your updated question. To get the running list you can do:
>> [reduce(lambda x,y: (x[0]+y[0], x[1]+y[1]), lst[:i]) for i in range(1,len(lst)+1)]
[(0, 0), (2, 3), (6, 6), (11, 7)]
Not super efficient, but at least it works and does what you want :)
This works for any length of tuples or other iterables.
from collections import defaultdict
def accumulate(lst):
sums = defaultdict(int)
for item in lst:
for index, subitem in enumerate(item):
sums[index] += subitem
yield [sums[index] for index in xrange(len(sums))]
print [tuple(x) for x in accumulate([(0, 0), (2, 3), (4, 3), (5, 1)])]
In Python 2.7+ you would use a Counter instead of defaultdict(int).
This is a really poor way (in terms of performance) to do this because list.append is expensive, but it works.
last = lst[0]
new_list = [last]
for t in lst[1:]:
last += t
new_list.append(last)
Simple method:
>> x = [(0, 0), (2, 3), (4, 3), (5, 1)]
>>> [(sum(a for a,b in x[:t] ),sum(b for a,b in x[:t])) for t in range(1,len(x)+1)]
[(0, 0), (2, 3), (6, 6), (11, 7)]
lst = [(0, 0), (2, 3), (4, 3), (5, 1)]
lst2 = [lst[0]]
for idx in range(1, len(lst)):
newItem = [0,0]
for idx2 in range(0, idx + 1):
newItem[0] = newItem[0] + lst[idx2][0]
newItem[1] = newItem[1] + lst[idx2][1]
lst2.append(newItem)
print(lst2)
You can use the following function
>>> def my_accumulate(lst):
new_lst = [lst[0]]
for x, y in lst[1:]:
new_lst.append((new_lst[-1][0]+x, new_lst[-1][1]+y))
return new_lst
>>> lst = [(0, 0), (2, 3), (4, 3), (5, 1)]
>>> my_accumulate(lst)
[(0, 0), (2, 3), (6, 6), (11, 7)]
Changed my code to a terser version:
lst = [(0, 0), (2, 3), (4, 3), (5, 1)]
def accumulate(the_list):
the_item = iter(the_list)
accumulator = next(the_item)
while True:
yield accumulator
accumulator = tuple(x+y for (x,y) in zip (accumulator, next(the_item)))
new_lst = list(accumulate(lst))

Remove ' from python list

I have a list, that looks like this in python:
ex = ['(1..3),(5..8)']
I need to get out the list like this:
[(1, 3), (5, 8)]
I tried using the replace function, but could only get like
['(1, 3), (5,8)'] and could not lose the ' marks.
Hope someone can help me.
Thanks
import ast
ex = ['(1..3),(5..8)']
list(ast.literal_eval(ex[0].replace('..', ',')))
# returns [(1, 3), (5, 8)]
ast.literal_eval is safe. eval is not.
For your updated question:
ex2 = ['(2..5)', '(7..10)']
[ast.literal_eval(a.replace('..', ',')) for a in ex2]
# returns [(2, 5), (7, 10)]
Look like some regex task.
>>> import re
>>> ex = ['(1..3),(5..8)']
>>> re.findall(r'\((\d+)\.\.(\d+)\)', ex[0])
[('1', '3'), ('5', '8')]
>>> # if you want tuple of numbers
... [tuple(map(int, x)) for x in _]
[(1, 3), (5, 8)]
This became uglier than I expected:
In [26]: ex = ['(1..22),(3..44)']
In [27]: [tuple([int(i) for i in s.strip('()').split('..')])
for s in ex[0].split(',')]
Out[27]: [(1, 22), (3, 44)]
if your format is constant, this should work :
>>> n = list(eval(ex[0].replace("..",",")))
>>> n
[(1, 3), (5, 8)]
UPDATE :
using literal eval ( safer ):
import ast
result = list(ast.literal_eval(ex[0].replace("..",",")))

Categories