how to create a column of ascending numbers by a certain value? - python

How do I make a list or column in pandas which number in this column increase itself by step of 1 and when it hits an certain number (let's say 5) it return to 1 and repeat this process?
My scripts like below and it won't work as expected:
i = 0
lista = []
for i in range(50):
i += 1
if i == 5:
continue
lista.append(i)
print(i)
# what I wanted from this code is like :
1
2
3
4
5
.
.
.
# repeat printing 1-5 for 10 times

First using loops in pandas is antipattern, mainly if exist vectorized solutions, here numpy.tile:
df = pd.DataFrame({'col': np.tile(np.arange(1, 6), 10)})
print (df.head(12))
col
0 1
1 2
2 3
3 4
4 5
5 1
6 2
7 3
8 4
9 5
10 1
11 2

In the simplest way that occurs to me:
lista = []
for i in range(50):
lista.append(i%5+1)
print(lista)
This could also be written as a list comprehension, which is only one line of code and way cooler ;)
lista = [ i%5+1 for i in range(50) ]

Related

python panda apply compare to external list and remove part of list

I have a parking lot with cars of different models (nr) and the cars are so closely packed that in order for one to get out one might need to move some others. A little like a 15Puzzle, only I can take one or more cars out of the parking lot. Ordered_car_List includes the cars that will be picked up today, and they need to be taken out of the parking lot with as few non-ordered cars as possible moved. There are more columns to this panda, but this is what I can't figure out.
I have a Program that works good for small sets of data, but it seems that this is not the way of the PANDAS :-)
I have this:
cars = pd.DataFrame({'x': [1,1,1,1,1,2,2,2,2],
'y': [1,2,3,4,5,1,2,3,4],
'order_number':[6,6,7,6,7,9,9,10,12]})
cars['order_number_no_dublicates_down'] = None
Ordered_car_List = [6,9,9,10,28]
i=0
while i < len(cars):
temp_val = cars.at[i, 'order_number']
if temp_val in Ordered_car_List:
cars.at[i, 'order_number_no_dublicates_down'] = temp_val
Ordered_car_List.remove(temp_val)
i+=1
If I use cars.apply(lambda..., how can I change the Ordered_car_List in each iteration?
Is there another approach that I can take?
I found this page, and it made me want to be faster. The Lambda approach is in the middle when it comes to speed, but it still is so much faster than what I am doing now.
https://towardsdatascience.com/how-to-make-your-pandas-loop-71-803-times-faster-805030df4f06
Updating cars
We can vectorize this based on two counters:
cumcount() to cumulatively count each unique value in cars['order_number']
collections.Counter() to count each unique value in Ordered_car_List
cumcount = cars.groupby('order_number').cumcount().add(1)
maxcount = cars['order_number'].map(Counter(Ordered_car_List))
# order_number cumcount maxcount
# 0 6 1 1
# 1 6 2 1
# 2 7 1 0
# 3 6 3 1
# 4 7 2 0
# 5 9 1 2
# 6 9 2 2
# 7 10 1 1
# 8 12 1 0
So then we only want to keep cars['order_number'] where cumcount <= maxcount:
either use DataFrame.loc[]
cars.loc[cumcount <= maxcount, 'nodup'] = cars['order_number']
or Series.where()
cars['nodup'] = cars['order_number'].where(cumcount <= maxcount)
or Series.mask() with the condition inverted
cars['nodup'] = cars['order_number'].mask(cumcount > maxcount)
Updating Ordered_car_List
The final Ordered_car_List is a Counter() difference:
Used_car_List = cars.loc[cumcount <= maxcount, 'order_number']
# [6, 9, 9, 10]
Ordered_car_List = list(Counter(Ordered_car_List) - Counter(Used_car_List))
# [28]
Final output
cumcount = cars.groupby('order_number').cumcount().add(1)
maxcount = cars['order_number'].map(Counter(Ordered_car_List))
cars['nodup'] = cars['order_number'].where(cumcount <= maxcount)
# x y order_number nodup
# 0 1 1 6 6.0
# 1 1 2 6 NaN
# 2 1 3 7 NaN
# 3 1 4 6 NaN
# 4 1 5 7 NaN
# 5 2 1 9 9.0
# 6 2 2 9 9.0
# 7 2 3 10 10.0
# 8 2 4 12 NaN
Used_car_List = cars.loc[cumcount <= maxcount, 'order_number']
Ordered_car_List = list(Counter(Ordered_car_List) - Counter(Used_car_List))
# [28]
Timings
Note that your loop is still very fast with small data, but the vectorized counter approach just scales much better:

How do you use the range function to count from 0 to 8 by increments of 1 for each iteration in a for loop

I have a triple for loop that creates a 1 row and 2 column collection of numbers starting at 0 0 and going up to 2 2. The third for loop counts from 0 to 8. The code looks as follows:
for N in range(0,3):
for K in range(0,3):
print(N,K)
for P in range(0,9):
print(P)
If you run this code you get the obvious output:
0 0
0
1
2
3
4
5
6
7
8
0 1
0
1
2
3
4
5
6
7
8
0 2
0
1
2
3
4
5
6
7
8
...
And so on. I want instead of the output of 0 to 8 after the N K printout, instead something that looks like:
0 0
0
0 1
1
0 2
2
1 0
3
1 1
4
1 2
5
2 0
6
2 1
7
2 2
8
My first guess was an if statement that said:
if P == Q:
break
where Q was several sets of sums and even the N,K array. However, I couldn't figure out the best way to get my
wanted output. I do think an if statement is the best way to achieve my wanted result, but I'm not quite sure of how to approach it. P is necessary for the rest of my code as it will be used in some subplots.
As this is just an increment by one at each print, you can just do compute the index with N * 3 + K
for N in range(0, 3):
for K in range(0, 3):
print(N, K)
print(N * 3 + K)
CODE DEMO
You can use zip to traverse two iterables in parallel. In this case, one of the iterables is the result of a nested list. That can be handled by using itertools.product, as follows:
import itertools
for (N, K), P in zip(itertools.product(range(3), range(3)), range(9)):
print(N, K)
print(P)

How to print a sequence stacked in a "pyramid" with alternating sort?

I want to print the following sequence of integers in a pyramid (odd rows sorted ascending, even rows sorted descending). If S=4, it must print four rows and so on.
Expected output:
1
3 2
4 5 6
10 9 8 7
I tried out the following code but it produced the wrong output.
S=int(input())
for i in range(1,S+1):
y=i+(i-1)
if i%2!=0:
print(*range(i,y+1))
elif i%2==0:
print(*range(y,i-1,-1))
# Output:
# 1
# 3 2
# 3 4 5
# 7 6 5 4
You need some way of either keeping track of where you are in the sequence when printing each row, generating the entire sequence and then chunking it into rows, or... (the list of possible approaches goes on and on).
Below is a fairly simple approach that just keeps track of a range start value, calculates the range stop value based on the row number, and reverses even rows.
rows = int(input())
start = 1
for n in range(1, rows + 1):
stop = int((n * (n + 1)) / 2) + 1
row = range(start, stop) if n % 2 else reversed(range(start, stop))
start = stop
print(*row)
# If rows input is 4, then output:
# 1
# 3 2
# 4 5 6
# 10 9 8 7
Using itertools.count and just reversing the sublist before printing on even rows
from itertools import count
s = 4
l = count(1)
for i in range(1, s+1):
temp = []
for j in range(i):
temp.append(next(l))
if i % 2:
print(' '.join(map(str, temp)))
else:
print(' '.join(map(str, temp[::-1])))
1
3 2
4 5 6
10 9 8 7

Keeping Python from spacing after breaking a line when printing a List

(yes, I've searched all around for a solution, and, if did I see it, I wasn't able to relate to my issue. I'm new to Python, sorry!)
I've got a work to do, and it says to me:
"User will input X and Y. Show a sequence from 1 to Y, with only X elements each line."
e.g
2 4 as entrance
1 2
3 4
e.g 2 6
1 2
3 4
5 6
Okay... So, I thought on doing this:
line, final = input().split()
line = int(line)
final = int(final)
List = []
i = 0
total = (final // line)
spot = 0
correction = 0
k = 1
if i != final:
List = list(range(1, final + 1, 1))
i += 1
while k != total:
spot = line * k + correction
correction += 1
k += 1
list.insert(List, spot, '\n')
print(*List)
Ok. So I managed to build my List from 1 to the "final" var.
Also managed to find on which spots (therefore, var "spot") my new line would be created. (Had to use a correction var and some math to reach it, but it's 10/10)
So far, so good.
The only problem is this work is supposed to be delivered on URI Online Judge, and it DEMANDS that my result shows like this:
2 10 as entrance
1 2
3 4
5 6
7 8
9 10
And, using the code I just posted, I get this as a result:
1 2
3 4
5 6
7 8
9 10
Thus, it says my code is wrong. I've tried everything to remove those spaces (I think). Using sys won't work since it only prints one argument. Tried using join (but I could have done it wrong, as I'm new anyway)
Well, I've tried pretty much anything. Hope anyone can help me.
Thanks in advance :)
You have built a list that includes each necessary character, including the linefeed. Therefore, you have a list like this:
[1, 2, '\n', 3, 4, '\n'...]
When you unpack arguments to print(), it puts a separator between each argument, defaulting to a space. So, it prints 1, then a space, then 2, then a space, then a linefeed, then a space... And that is why you have a space at the beginning of each line.
Instead of inserting linefeeds into a list, chunk that list with iter and next:
>>> def chunks(x, y):
... i = iter(range(1, y+1))
... for row in range(y//x):
... print(*(next(i) for _ in range(x)))
... t = tuple(i)
... if t:
... print(*t)
...
>>> chunks(2, 6)
1 2
3 4
5 6
>>> chunks(2, 7)
1 2
3 4
5 6
7
The problem with the approach you're using is a result of a space being printed after each "\n" character in the series. While the idea was quite clever, unfortunately, I think this means you will have to take a different approach from inserting the newline character into the list.
Try this approach: (EDITED)
x, y = input().split()
x, y = int(x), int(y)
for i in range(1, y+1):
if i % x == 0 or i == y:
print(i)
else:
print(i, end=" ")
Output for 3 11
1 2 3
4 5 6
7 8 9
10 11
Output for 2 10
1 2
3 4
5 6
7 8
9 10
Use itertools to take from an iterable in chunks:
>>> import itertools
>>> def print_stuff(x,y):
... it = iter(range(1, y + 1))
... chunk = list(itertools.islice(it,X))
... while chunk:
... print(*chunk)
... chunk = list(itertools.islice(it,X))
...
>>> print_stuff(2,4)
1 2
3 4
>>>
And here:
>>> print_stuff(2,10)
1 2
3 4
5 6
7 8
9 10
>>>
I split user input into two string then convert them into int and comapre if y greater than x by 2 because this is minimum for drawing your sequence
Then i make a list from 1 to y
And iterate over it 2 element for each iteration printing them
x,y=input().split()
if int(y)>int(x)+2:
s=range(1,int(y)+1)
for i in range(0,len(s),2):
print(' '.join(str(d) for d in s[i:i+2]))
result:
1 2
3 4
5 6
7 8
9 10

Aligning text in a table using string formatting with a loop inside a loop

I'm supposed to align some numbers in a table while using a loop inside a loop. It should look like this when it's done:
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
What I've stared with is:
for i in range(1,10,1):
for c in range(1,6,1):
print(i, end='\n')
Though after running this it just prints them bellow each other. And replacing "\n" with "\t" doesn't help either. I've tried .format but with no success. Sorry if this seems very simple and that it should be stated somewhere but I can't find someone with the same problem or some chapter referring to this specific problem.
I did manage to do this table by using while like this:
i = 1
while i < 6:
print("1 2 3 4 5 6 7 8 9\n" , end='' '')
i += 1
This is of course not the best way to do it, I just don't have the knowledge to do it in a smarter way.
First, you have inverted loop ranges it should be:
for i in range(1, 6, 1):
for c in range(1, 10, 1):
Second, in the inner loop you have to print c, not i.
The full code would be like this:
for i in range(1, 6, 1):
for c in range(1, 10, 1):
print(c, end=" ")
print('')
If you want to code only one for loop you can:
for i in range(1, 6, 1):
print( " ".join(map(str, range(1, 10, 1))) )
Firstly, your loops are in the wrong order. As you write your code, you will get 10 rows with 6 numbers.
Next, you can't print in the inner loop, because you will get just 60 rows. So you can store rows in some temp value inside first loop, and on each cycle of outer loop print it. Also, for more pretty code, you can use list comprehensions.
for i in range(1, 10):
print ' '.join([str(number) for number in range(1, 6)])
Also, to perfect this, you can write it in 1 string of code, but this is more understandable.

Categories