Python 3.x : I'm out of range - python-3.x

I'm asking to have some help cause I believe I know why I'm out of range but I don't know out to solved it. Thanks you :D
#Import input.
from pathlib import Path
test = Path(r'C:\Users\Helphy\Desktop\Perso\GitHub\Advent_of_Code_2021\Day_3\Input.txt').read_text().split("\n")
#Defined some variable
temp = []
finalnumtemp = []
finalnum = []
f_num = []
zero = 0
one = 0
for t in range(len(test)):
for j in range(len(test)):
temp = list(test[j])
print(temp)
finalnumtemp.append(temp[j])
print(finalnumtemp)
"""for i in range(len(finalnumtemp)):
if int(finalnumtemp[i]) == 0:
zero += 1
else:
one += 1
if zero > one:
finalnum.append(0)
else:
finalnum.append(1)
zero == 0
one == 0
finalnumtemp = []
print(finalnum)"""
Input :
00100
11110
10110
10111
10101
01111
00111
11100
10000
11001
00010
01010
error: An exception has occurred: IndexError
list index out of range
File "C: \ Users \ Helphy \ Desktop \ Perso \ GitHub \ Advent_of_Code_2021 \ Day_3 \ Day_3.py", line 16, in <module>
finalnumtemp.append (temp [j])

What to solve? What did you intend for the program to achieve?
You have an error because...
j goes from 0 to len(test), that is, 12
test[j] as temp has only 5 elements.
To select among the digits in temp, the index should be something of 0, 1, 2, 3, 4 (first, second, third, ... from the left) or -1, -2, -3, -4, -5 (first, second, third, ... from the right).
To append the first of temp to finalnumtemp, fix
finalnumtemp.append(temp[j])
to
finalnumtemp.append(temp[0])

Maybe you should look into list comprehension. I know it is maybe a bit daunting at first but I personally found it to make much more sense than nested for loops after I had gotten the hang of them. You could convert your strings of zeros and ones into lists of separate integers in a single line:
numbers = [[int(char) for char in line] for line in test]
[[0, 0, 1, 0, 0], [1, 1, 1, 1, 0], ... , [0, 0, 0, 1, 0], [0, 1, 0, 1, 0]]
And then fetch the first number (or any number really):
first_num = [num[0] for num in numbers]
[0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0]
And even perform operations on the lists if you wish:
sum_num = [sum(num) for num in numbers]
[1, 4, 3, 4, 3, 4, 3, 3, 1, 3, 1, 2]
Nested for loops can get real messy real quick. I know this isn't the actual answer to the question, but I thought it might be helpful regardless.

Related

Generate all n-bit binary bit patterns in order of their sum

I need a generator that yields every bit pattern of n bits in order of their sum (and more). For example for n=3,
1. sum([0, 0, 0]) = 0 ✓
2. sum([1, 0, 0]) = 1 ✓
3. sum([0, 1, 0]) = 1 ✓
4. sum([1, 1, 0]) = 2 ⨯ should be swapped with 5.
5. sum([0, 0, 1]) = 1 ⨯
6. sum([1, 0, 1]) = 2 ✓
7. sum([0, 1, 1]) = 2 ✓
8. sum([1, 1, 1]) = 3 ✓
Note that even though 3 and 5 have the same sum, 5 should be generated after 3. The correct order would have been, 000, 100, 010, 001, 110, 101, 011, 111. The idea here is that if this (2ⁿ, n) dimension matrix was multiplied by a (n, 1) vector that is sorted in ascending order than the product would be sorted as well. Eliminating the need to sort this product will help in optimising an experiment I am trying to run.
Here is my rather inefficient and incomplete attempt,
def forwards(n):
ls = [0]*n
for i in range(n):
for j in range(n-i):
copy = list(ls)
copy[j] = 1
yield copy
ls[-(i+1)] = 1
As you can see, this does get the order right but misses some patterns.
Here is another somewhat efficient but wrong order attempt.
def forwards(n):
for i in range(1 << n):
yield [(i >> k) & 1 for k in range(n)]
This one generates all patterns but in the wrong (shown in the example above) order.
I need this function to be efficient so solutions where a string is generated and then characters are converted to integers are discouraged.
Lastly, I am working in Python 3.9. You can use Numpy.
I believe this gives you the order you want:
First, sort in ascending order by number of 1's
Next, sort in descending order by lexicographical order
from itertools import combinations
def forwards(n):
for one_bits in range(n + 1):
for combination in combinations(range(n), one_bits):
yield [1 if x in combination else 0 for x in range(n)]
for x in forwards(4):
print("{}, one bits = {}, binary value = {}".format(x, sum(x), sum(x[i] * 2**(3 - i) for i in range(4))))
This works by handling the first condition in the first for loop for one_bits in range(n + 1):, and generating all possible N-sized combinations of indices between 0 and n - 1, and then those indices are set to 1, else 0.
This prints
[0, 0, 0, 0], one bits = 0, binary value = 0
[1, 0, 0, 0], one bits = 1, binary value = 8
[0, 1, 0, 0], one bits = 1, binary value = 4
[0, 0, 1, 0], one bits = 1, binary value = 2
[0, 0, 0, 1], one bits = 1, binary value = 1
[1, 1, 0, 0], one bits = 2, binary value = 12
[1, 0, 1, 0], one bits = 2, binary value = 10
[1, 0, 0, 1], one bits = 2, binary value = 9
[0, 1, 1, 0], one bits = 2, binary value = 6
[0, 1, 0, 1], one bits = 2, binary value = 5
[0, 0, 1, 1], one bits = 2, binary value = 3
[1, 1, 1, 0], one bits = 3, binary value = 14
[1, 1, 0, 1], one bits = 3, binary value = 13
[1, 0, 1, 1], one bits = 3, binary value = 11
[0, 1, 1, 1], one bits = 3, binary value = 7
[1, 1, 1, 1], one bits = 4, binary value = 15

Replace values in a list based on condition of previous value

I would like to modify a list that has 3 different numbers [0, 1, 2]
Each 0 should be replaced with either the last 1 or 2 value depending on which was most recent during the iteration.
Is it possible to create the new list using a list comprehension?
I know I can use a for loop and just record the last 1 or 2 and append the values to the new list but I prefer the most pythonic way.
list = [1, 1, 2, 1, 0, 0, 1, 0, 2, 0, 0]
new_list = [1, 1, 2, 1, 1, 1, 1, 2, 2, 2]
I was using this but then realised that after 2 0s in a sequence it would start recording 0s again.
new_list = [list[index-1] if list[index] == 0 else value for index,value in enumerate(list)]
Starting in python 3.8 you now have the walrus operator := which can assign values as part of an expression and works in list comprehensions. You just need to decide what the first value will be if the list starts with 0 since there is no previous value:
alist = [1, 1, 2, 1, 0, 0, 1, 0, 2, 0, 0]
j = 0
[j:= i if i else j for i in alist]
# [1, 1, 2, 1, 1, 1, 1, 1, 2, 2, 2]
Perform that just with a list comprehension could be a little weird, so here my solution (without creating a new list):
my_list = [1, 1, 2, 1, 0, 0, 1, 0, 2, 0, 0]
last_not_zero = 0
for index, number in enumerate(my_list):
if number!=0:
last_not_zero = number
else:
my_list[index] = last_not_zero
print(my_list)
And you'll get:
[1, 1, 2, 1, 1, 1, 1, 1, 2, 2, 2]
If you have a large list or you are using Pandas in your code,
import pandas as pd
s = pd.Series(list)
s.replace(0, pd.np.nan).ffill().to_list()
Output
[1, 1, 2, 1, 1, 1, 1, 1, 2, 2, 2]
NOTE: If you are not using pandas/numpy in your code, then basic for loop would be the best way to do this. Advise using the above code only for large arrays with multiple manipulations.
How about this
last_value = 0
new_list = []
for value in list:
if value != 0:
last_value = value
new_list.append(value)
else:
new_list.append(last_value)
Depends on the condition.
In most cases, you can place the condition within the while loop in the if-else criteria statements.
If, say, you want to replace the content of a list if the previous value was
something,
size = len(list)
while True:
index = index + 1
if index!=0 and index<size:
if list[index-1]==something:
list[index] = value to be replaced
if index == (size-1):
a = 0
for a in (0, (size-1)):
print(a,":",list(a))
break

How to return the last index of a group in a list Python

I have a list in following form:
[0, 0, 0, 0, 1, 1, 1, 0.6, 0.6, 0, 0, 0]
each of the items in the list is a small decimal number. I'm looking for a way of returning the last index position of each group. In the above example it would be something like:
0: 3, 1: 6, 0.6: 8, 0: 11
I'm fairly new to python and I don't really know how to approach this
itertools.groupby may be useful here, it deals with pretty much everything except tracking the indices which isn't hard to do yourself:
import itertools
a = [0, 0, 0, 0, 1, 1, 1, 0.6, 0.6, 0, 0, 0]
i = 0
for val, group in itertools.groupby(a):
for inst in group:
# each element that is the same in sequence, increment index
i += 1
# after the inner for loop i will be the index of the first element of next group
# so i - 1 is the index of last occurence.
print(val, i - 1)
If you are particularly clever with enumerate and variable unpacking you can make this super short although less obvious how it's working.
import itertools
from operator import itemgetter
a = [0, 0, 0, 0, 1, 1, 1, 0.6, 0.6, 0, 0, 0]
# still group only by value but now use enumerate to have it keep track of indices
for val, group in itertools.groupby(enumerate(a), itemgetter(1)):
# this is tuple unpacking, irrelevant is a list of values that aren't the last one, and last is the one we care about.
[*irrelevent, last] = group
print(last)
This answer is less intended to say "here's how you should do it" and more "this is some of the things that exist in python", happy coding :)
Try this :
a=[0, 0, 0, 0, 1, 1, 1, 0.6, 0.6, 0, 0, 0]
i=0
while(i<=len(a)):
if (i == len(a)-1):
print(str(a[i]) + ":" + str(i))
break
if(a[i]!=a[i+1]):
print(str(a[i])+":"+str(i))
i=i+1

Print statement working in function but not in body of the code

Python beginner here
I`m writing a script to solve sudoku. Most of the code is taken from this video.
The function works and prints the solved grid as long as my print statement is in the function, but when I put it outside the function it prints out the original array and not the solved array.
Any idea why this is happening and on how can I access the solved array outside the function in the body of the code.
You all can ignore testing the functions because they work as the solved array is getting printed from the function, my problem is how to get it printed and access it from the body.
I would like print statements 3 or 4 to be the solved array.
Any help would be appreciated.
import numpy as np
sudoku_grid = np.array([[4, 0, 0, 0, 0, 1, 6, 3, 7],
[0, 6, 0, 0, 4, 0, 0, 5, 1],
[0, 0, 0, 6, 3, 0, 0, 0, 0],
[0, 2, 0, 0, 0, 8, 1, 0, 0],
[6, 0, 8, 9, 0, 5, 3, 0, 4],
[0, 0, 1, 4, 0, 0, 0, 8, 0],
[0, 0, 0, 0, 9, 3, 0, 0, 0],
[7, 8, 0, 0, 6, 0, 0, 1, 0],
[2, 3, 6, 1, 0, 0, 0, 0, 8]])
def possible(row, column, number, grid):
"""Checks whether a number can be inserted in a cell"""
# Checking for duplicate number in row
for i in range(9):
if number == grid[row, i]:
return False
# Checking for duplicate number in column
for j in range(9):
if number == grid[j, column]:
return False
# Checking for duplicate number in grid
# Returns 0,1,2 for row and column so basically 9X9 grid is reduced to 3X3 grid
and duplicated are checked within the same
r = row//3*3
c = column//3*3
for k in range(r, r+3):
for l in range(c, c+3):
if number == grid[k, l]:
return False
return True
def solve(grid):
"""Solves sudoku using recursion and back tracking"""
# use combination of row and column to get a cell
for i in range(9):
for j in range(9):
# if cell is zero then tries to enter number
if grid[i, j] == 0:
for k in range(1, 10):
# Checks if number is possible and enters the same in array
if possible(i, j, k, grid):
grid[i, j] = k
# Recursion moves to next cell
solve(grid)
# Backtracks if not possible
grid[i, j] = 0
# if no numbers are 0 then Solved and return array
return grid
print(grid, "\n Print statement 2(function print statement)")
print(sudoku_grid, "\n Print statement 1(Original grid b/f function)")
print("________________________")
x = solve(sudoku_grid)
print("________________________")
print(x, "\n Print statement 3")
print("________________________")
print(sudoku_grid, "\n Print statement 4")
According to your function solve, your code either:
returns a grid, or
prints a grid
Notice the return happens inside for cycle, and the print is after it. If the function had returned, no print would happen.
You never reach this part of code:
# if no numbers are 0 then Solved and return array
return grid
and that's because you're making a recursion without a condition:
# Recursion moves to next cell
solve(grid)
Notice that
# if cell is zero then tries to enter number
if grid[i, j] == 0:
for k in range(1, 10):
...
solve(grid)
...
# if no numbers are 0 then Solved and return array
return grid
is itself incoherent, because you're entering a condition where a 0 cell exists, but you expect a return if none is 0... and even if that would happen, the order of your statements will not let the grid to be returned, because a call to solve is being done before the return statement.
So, you must have a condition that will make you not call solve and return the grid instead - both in same scope/condition will not work.

how to fix python fibonacci sequence script?

My assignment is to create a function that produces 3 lists of the numbers in the fibonacci sequence starting at 0. Here is my code so far.
def fibList(n):
a = 0; b = 1; fibList = []
if n <= 0:
return
elif n == 1:
fibList = [a]
elif n == 2:
fibList = [a,b]
else:
for i in range(0,n):
a, b = b, a + b
fibList.append(b)
return fibList
def main():
print (fibList(4))
print (fibList(10))
print (fibList(-4))
what i want my output to look like is [0,1,1,2] for 4, [0,1,1,2,3,5,8,13,21,34,55] for 10, and [] for -4
My issue begins with fibList(4) currently giving an output of [1, 2, 3, 5] and fibList(10) gives an output of [1, 2, 3, 5, 8, 13, 21, 34, 55, 89] and for -4 I get "None" instead of a [].
If I type in fibList(1) I get [0] and for fibList(2) I get [0, 1], but when i test fibList(3) the first 0 and 1 are lost, giving me [1,2,3]
How would I go about making it so any number above 3 starts with [0, 1, 1, 2...]? My main issue is getting the 0 and 1 to be the first two numbers in the sequence and getting fibList(-4) to produce a [].
any help or tips would be greatly appreciated :-)
All that you are missing is to add an empty list in the case of less than or equal to zero, and recurse correctly over your range of Fibonacci numbers greater than 2. Making those small changes like so:
def fibList(n):
if n <= 0:
fibnums = []
elif n == 1:
fibnums = [0]
elif n >= 2:
fibnums = [0, 1]
for i in range(2,n):
fibnums.append(fibnums[i-1]+fibnums[i-2])
return fibnums
Note that this recursive method can get quite slow for large numbers, if that is of concern to you with your program. Best of luck!
With these changes,
print (fibList(4)) => [0, 1, 1, 2]
print (fibList(10)) => [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
print (fibList(-4)) => []
You did not quite define your function. Should the resulting list have n values [f(0), ..., f(n-1)] or n+1 values [f(0), ..., f(n)]? Your examples are contradictory: the 'expected' output for 4 has 4 values ending with f(3) while that for 10 has 11 values ending with f(10).
I am going to assume that the latter is correct. Here is a revised version of your fast iterative solution. (If my assumption is wrong, stop the range at n instead of n+1.)
def fibs(n):
"Return [fib(0), ..., fib(n)."
ret = [0, 1] # fib(0), fib(1)
a, b = ret
if n <= 1:
return ret[:n+1]
else:
for i in range(2, n+1):
a, b = b, a+b # b = f(i)
ret.append(b)
return ret
print(fibs(-4), fibs(0), fibs(2), fibs(4), fibs(10))
#
[] [0] [0, 1, 1] [0, 1, 1, 2, 3] [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

Resources