range() function is giving me trouble - python

If I were to type something like this, I would get these values:
print range(1,10)
[1,2,3,4,5,6,7,8,9]
but say if I want to use this same value in a for loop then it would instead start at 0, an example of what I mean:
for r in range(1,10):
for c in range(r):
print c,
print ""
The Output is this:
0
0 1
0 1 2
0 1 2 3
0 1 2 3 4
0 1 2 3 4 5
0 1 2 3 4 5 6
0 1 2 3 4 5 6 7
0 1 2 3 4 5 6 7 8
Why is 0 here? shouldn't it start at 1 and end in 9?

You are creating a second range() object in your loop. The default start value is 0.
Each iteration you create a loop over range(r), meaning range from 0 to r, exclusive, to produce the output numbers. For range(1) that means you get a list with just [0] in it, for range(1) you get [0, 1], etc.
If you wanted to produce ranges from 1 to r inclusive`, just add 1 to the number you actually print:
for r in range(1,10):
for c in range(r):
print c + 1,
print ""
or range from 1 to r + 1:
for r in range(1,10):
for c in range(1, r + 1):
print c,
print ""
Both produce your expected output:
>>> for r in range(1,10):
... for c in range(r):
... print c + 1,
... print ""
...
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
1 2 3 4 5 6
1 2 3 4 5 6 7
1 2 3 4 5 6 7 8
1 2 3 4 5 6 7 8 9
>>> for r in range(1,10):
... for c in range(1, r + 1):
... print c,
... print ""
...
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
1 2 3 4 5 6
1 2 3 4 5 6 7
1 2 3 4 5 6 7 8
1 2 3 4 5 6 7 8 9

If you pass only one argument to range function, it would treat that as the ending value (without including it), starting from zero.
If you pass two arguments to the range function, it would treat the first value as the starting value and the second value as the ending value (without including it).
If you pass three arguments to the range function, it would treat the first value as the starting value and the second value as the ending value (without including it) and the third value as the step value.
You can confirm this with few trial runs like this
>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # Default start value 0
>>> range(5, 10)
[5, 6, 7, 8, 9] # Starts from 5
>>> range(5, 10, 2)
[5, 7, 9] # Starts from 5 & takes only the 2nd element

Nope.
for r in range(1,10):
for c in range(r):
print c,
print ""
range(), when only given one argument, prints the numbers from 0 to the argument, not including the argument:
>>> range(6)
[0, 1, 2, 3, 4, 5]
And so, on the third iteration of your code, this is what happens:
for r in range(1,10): # r is 3
for c in range(r): # range(3) is [0,1,2]
print c, #you then print each of the range(3), giving the output you observe
print ""

https://docs.python.org/2/library/functions.html#range
From the docs:
The arguments must be plain integers. If the step argument is omitted, it defaults to 1. If the start argument is omitted, it defaults to 0.

Related

How to remove consecutive pairs of opposite numbers from Pandas Dataframe?

How can i remove consecutive pairs of equal numbers with opposite signs from a Pandas dataframe?
Assuming i have this input dataframe
incremental_changes = [2, -2, 2, 1, 4, 5, -5, 7, -6, 6]
df = pd.DataFrame({
'idx': range(len(incremental_changes)),
'incremental_changes': incremental_changes
})
idx incremental_changes
0 0 2
1 1 -2
2 2 2
3 3 1
4 4 4
5 5 5
6 6 -5
7 7 7
8 8 -6
9 9 6
I would like to get the following
idx incremental_changes
0 0 2
3 3 1
4 4 4
7 7 7
Note that the first 2 could either be idx 0 or 2, it doesn't really matter.
Thanks
Can groupby consecutive equal numbers and transform
import itertools
def remove_duplicates(s):
''' Generates booleans that indicate when a pair of ints with
opposite signs are found.
'''
iter_ = iter(s)
for (a,b) in itertools.zip_longest(iter_, iter_):
if b is None:
yield False
else:
yield a+b == 0
yield a+b == 0
>>> mask = df.groupby(df['incremental_changes'].abs().diff().ne(0).cumsum()) \
['incremental_changes'] \
.transform(remove_duplicates)
Then
>>> df[~mask]
idx incremental_changes
2 2 2
3 3 1
4 4 4
7 7 7
Just do rolling, then we filter the multiple combine
s = df.incremental_changes.rolling(2).sum()
s = s.mask(s[s==0].groupby(s.ne(0).cumsum()).cumcount()==1)==0
df[~(s | s.shift(-1))]
Out[640]:
idx incremental_changes
2 2 2
3 3 1
4 4 4
7 7 7

Turn list clockwise for one time

How I can rotate list clockwise one time? I have some temporary solution, but I'm sure there is a better way to do it.
I want to get from this
Index: 0 1 2 3 4 5 6 7 8 9
Count: 0 2 4 4 5 6 6 7 7 7
to this:
Index: 0 1 2 3 4 5 6 7 8 9
Count: 0 0 2 4 4 5 6 6 7 7
And my temporary "solution" is just:
temporary = [0, 2, 4, 4, 5, 6, 6, 7, 7, 7]
test = [None] * len(temporary)
test[0] = temporary[0]
for index in range(1, len(temporary)):
test[index] = temporary[index - 1]
You might use temporary.pop() to discard the last item and temporary.insert(0, 0) to add 0 to the front.
Alternatively in one line:
temporary = [0] + temporary[:-1]

Splitting values in the column and creating new cols small problem

I have an survey data in which one column is as follows:
Evaluations_Col
E: 3, D: 3, C: 3, S: 3, E: 3, X, K: 3
E: 1, D: 1, C: 1, S: 1, E: 1, X, K: 1
E: 2, D: 2, C: 2, S: 2, E: 2, X, K: 2
E: 5, D: 5, C: 5, S: 5, E: 5, X, K: 5
E: 3, D: 1, C: 1, S: 1, E: 1, X, K: 1
NOTE: I need to ignore X values in the columns.
I want to extract each evaluation and separate them as columns separately for each type of evaluation. and at the end expected columns will be like:
E_col D_col C_Col ...
3 3 3
1 1 1
2 2 2
5 5 5
3 1 1
I can maybe split them by comma and get a list like this, [E: 3, D: 3, C: 3, S: 3, E: 3, K: 3] What how to create seperate column for each and spread the corresponding values correctly?
I can achive normally by this but X values cause problem bc dictionary... How can I exclude it?
df1 = pd.DataFrame([dict([y.split(':') for y in x.split(',')]) for x in test_col])
df1.head()
error is
ValueError: dictionary update sequence element #9 has length 1; 2 is required
Using list comprehension and filtering lines that are with ':' separator only:
Let's break the list comprehension to parts:
Looping on lines : for x in test_col
Seperating only the lines (denoted by x) to colums by splitting by ',' : for y in x.split(',')
Splitting column to key-value pair only if ':' seperator exists : y.split(':') for y in x.split(',') ***only*** if ':' in y (that solves the problem described)
Code:
import pandas as pd
import numpy as np
test_col = []
with open('data.csv', 'r') as f:
test_col = [l.strip() for l in f.readlines()]
df = pd.DataFrame([dict([y.split(':') for y in x.split(',') if ':' in y]) for x in test_col])
print(df.head())
Output:
E D C S E K
0 3 3 3 3 3 3
1 1 1 1 1 1 1
2 2 2 2 2 2 2
3 5 5 5 5 5 5
4 3 1 1 1 1 1
One way is to use str.extractall:
s = df["Value"].str.extractall(r"([A-Z]):\s(\d)").reset_index().groupby("level_0")
print (pd.DataFrame(s[1].agg(list).tolist(), columns=s[0].get_group(0).tolist()))
E D C S E K
0 3 3 3 3 3 3
1 1 1 1 1 1 1
2 2 2 2 2 2 2
3 5 5 5 5 5 5
4 3 1 1 1 1 1
using str.split and stack
df1 = (
df["Evaluations_Col"]
.str.split(",", expand=True)
.stack()
.str.split(":", expand=True)
.set_index(0, append=True)
.dropna()
.unstack([1, 2])
.droplevel(1,1)
)
1
0 E D C S E K
0 3 3 3 3 3 3
1 1 1 1 1 1 1
2 2 2 2 2 2 2
3 5 5 5 5 5 5
4 3 1 1 1 1 1

Python. Creating a table from a 2D array with numbered rows

t = [[1, 2, 3, 4, 5, 6], [2, 4, 6, 8,
i = 0
a = 0
for i in range(len(t)):
for a in range(len(t[i])):
print(a+1, t[i][a], end=' ')
print('\n', end='')
My expected output would be (in more general terms):
a+1 t[i][a] t[i]+[a+2]...
a+2 t[i+1][a]...
and so on.
For example (with 2D-array t):
1 1 2 3 4 5 6
2 2 4 6 8 10 12
Instead with the above code I get:
1 1 2 2 3 3 4 4 5 5 6 6
1 2 2 4 3 6 4 8 5 10 6 12
And I cannot pinpoint exactly why. Any ideas?
You have a small mistake, as you print a+1 inside the inner loop. You should print i+1 inside the outer loop.
for i, _ in enumerate(t):
print(i+1, end=' ');
for a, _ in enumerate(t[i]):
print(t[i][a], end=' ')
print('\n', end='')

generating sequences with arbitrary distance between consecutive members

I'm trying to write a function that will take as input length L and distance D (both integers > 1) and output all possible sequences that fit the following parameters:
start with the number 1
have L elements
have a distance of 1 to D between each element and the following element
So, for L = 4 and D = 2, the possible sequences would be:
1 2 3 4 (distance of 1 between each consecutive element)
1 2 3 5
1 2 4 5
1 2 4 6
1 3 4 5
1 3 4 6
1 3 5 6
1 3 5 7 (distance of 2 between each consecutive element)
Or, for L = 3 and D = 3, the possible sequences would be:
1 2 3 (distance of 1 between each consecutive element)
1 2 4
1 2 5
1 3 4
1 3 5 (distance of 2 between each consecutive element)
1 3 6
1 4 5
1 4 6
1 4 7 (distance of 3 between each consecutive element)
From hand-coding several of these, the number of possible sequences seems to be D ** (L-1). At first I only needed 2\**7, and 128 sequences wasn't that difficult to create by hand. However, I now need 3**7, and possibly even larger amounts, so I need to write a function.
Python is the language I'm learning. Recursion seems to be the way to do it, but I've only practiced on simple recursion, and I'm stuck as to how precisely to write this. As best as I can work out, I need a function that calls itself from within a for-loop. Does this make sense? Directions to similarly structured functions would be greatly appreciated, as well.
You can use itertools.product and itertools.accumulate to achieve your desired function:
import itertools
def f(l, d):
for sub in itertools.product(range(1, d+1), repeat=l-1):
yield tuple(itertools.accumulate((1,) + sub))
for l in f(4, 2):
print(l)
(1, 2, 3, 4)
(1, 2, 3, 5)
(1, 2, 4, 5)
(1, 2, 4, 6)
(1, 3, 4, 5)
(1, 3, 4, 6)
(1, 3, 5, 6)
(1, 3, 5, 7)
Here is a quick and dirty implementation
def gen_seq(D, L):
for uple in itertools.product(range(1, D+1), repeat=L-1):
yield tuple(numpy.cumsum((1,) + uple))
The point of recursion is not only formalizing the code in a recursive way, but orientating your mind in a recursive way. Compare carefully the results for length 3 and length 4 with distance 2.
a. Length 3
1 2 3
1 2 4
1 3 4
1 3 5
b. Length 4
1 2 3 | 4
1 2 3 | 5
1 2 4 | 5
1 2 4 | 6
1 3 4 | 5
1 3 4 | 6
1 3 5 | 6
1 3 5 | 7
In the result of length 4, the right side of | is just the result of length 3. That means the result of N length can be derived from N - 1 length.
Assume that we have already a procedure to solve k - 1 length solve_part(k-1), by extending the result of k-1 to next length k next_len(solve_part(k-1) ...), this problem is naturally solved in a recursive way.
import itertools
def flatmap(func, *iterable):
return itertools.chain.from_iterable(map(func, *iterable))
def next_distance(eachlist, D):
return map(lambda eachdis: eachlist + [eachlist[-1] + eachdis], range(1,D+1))
def next_len(L,D):
return flatmap(lambda eachlist: next_distance(eachlist, D), L)
def solve_it(leng,dis):
def solve_part(k):
if k == 0:
return [[]]
elif k == 1:
return [[1]]
else:
return next_len(solve_part(k-1),dis)
return solve_part(leng)
result=solve_it(4,2)
print([[i for i in j] for j in result])

Categories

Resources