Why does the other list change as well? [duplicate] - python

This question already has answers here:
How do I clone a list so that it doesn't change unexpectedly after assignment?
(24 answers)
Closed 7 years ago.
I have already solved problem 5 of Project Euler (What is the smallest positive number that is evenly divisible (with no remainder) by all of the numbers from 1 to 20?), but I want to find a faster way (currently 0.000109195709229 seconds).
I tried a dynamic approach, but when I run the code below (it is just the first part) I don't understand why d[var][counter] gets +1 if I explicitly wrote d[i][counter] += 1.
n = 20
d = {1:[0,1] + [0]*19} #a dictionary that assigns to each number a list of its prime factorization
for i in xrange(2,3): #I changed n+1 with 3 for simplicity
var = i
counter = 2
notDone = True
while notDone:
if var % counter == 0:
var /= counter
print var, d[var]
d[i] = d[var] #i has the same prime factorization of var ...
print var, d[var]
d[i][counter] += 1 #... except for 1 number (counter)
print var, d[var] #wtf?
notDone = False
else:
counter += 2 if counter != 2 else 1
This is the outcome:
1 [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
1 [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
1 [0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
why does this happen?

At the line
d[i] = d[var]
the variable d[i] will hold the same list object as d[var], as lists are mutable.
Instead you need a copy of d[var], that you can get e.g. by
d[i] = d[var][:]

Related

Stream generator. Limitations of output in an infinite iterator

I'm trying to figure out how an iterator works with this example:
There is the function that produces stream generator for given iterable object (list, generator, etc) whose elements contain position and value and sorted by order of apperance.
Stream generator is equal to initial stream (without position), gaps filled with zeroes.
from itertools import count
def gen_stream(total, sorted_iterable, extractor=lambda x: x):
sorted_iterator = iter(sorted_iterable)
iterable = count() if total is None else range(total)
try:
current_extracted_record = extractor(next(sorted_iterator))
except StopIteration:
current_extracted_record = None
for i in iterable:
if current_extracted_record:
if i == current_extracted_record[0]:
try:
yield current_extracted_record[1]
current_extracted_record = extractor(next(sorted_iterator))
except StopIteration:
current_extracted_record = None
else:
yield 0
else:
yield 0
Here are other, most likely, more advanced options for writing this function.
For example:
gen = gen_stream(9,[(4,111),(7,12)])
list(gen)
[0, 0, 0, 0, 111, 0, 0, 12, 0] # first element has zero index, so 111 located on fifth position, 12 located on 8th position
This function also support custom position-value extractor for more advanced cases, e.g.
def day_extractor(x):
months = [31, 28, 31, 30, 31, 31, 30, 31, 30, 31, 30, 31]
acc = sum(months[:x[1] - 1]) + x[0] - 1
return acc, x[2]
precipitation_days = [(3,1,4),(5,2,6)]
list(gen_stream(59,precipitation_days,day_extractor)) #59: January and February to limit output
[0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
precipitation_days format is following: (d,m,mm), where d - day in month, m - month, mm - precipitation in millimeters
So, in example:
(3,1,4) # January,3 precipitation: 4 mm
(5,2,6) # February,5 precipitation: 6 mm
Extractor passed as optional third parameter with default value - lambda function that handles (position, value) pairs like in first example.
Question 4
Following the example of this statement
print(list(gen_stream(59, precipitation_days, day_extractor)))
How to add examples with None (instead 59) but limit output using the loop for.
Answer
gen = gen_stream(None, [(4, 111), (7, 12)])
print([next(gen) for _ in range(20)], '\n')

How to write a A-star search algorithm to visit all the nodes without a specific end-point?

I am trying to write an algorithm to collect as many as possible items from different stops. which every stop is a cell in a matrices. the goal is to find the shortest path to collect all the items. The start point is defined, but the end-point can be anywhere... I used the A-star search algorithm for it...
Here is code:
import numpy as np
class Node:
"""
A node class for A* Pathfinding
parent is parent of the current Node
position is current position of the Node in the maze
g is cost from start to current Node
h is heuristic based estimated cost for current Node to end Node
f is total cost of present node i.e. : f = g + h
"""
def __init__(self, parent=None, position=None):
self.parent = parent
self.position = position
self.g = 0
self.h = 0
self.f = 0
def __eq__(self, other):
return self.position == other.position
#This function return the path of the search
def return_path(current_node,maze):
path = []
no_rows, no_columns = np.shape(maze)
# here we create the initialized result maze with -1 in every position
result = [[-1 for i in range(no_columns)] for j in range(no_rows)]
current = current_node
while current is not None:
path.append(current.position)
current = current.parent
# Return reversed path as we need to show from start to end path
path = path[::-1]
start_value = 0
# we update the path of start to end found by A-star serch with every step incremented by 1
for i in range(len(path)):
result[path[i][0]][path[i][1]] = start_value
start_value += 1
return result
def search(maze, cost, start, end):
"""
Returns a list of tuples as a path from the given start to the given end in the given maze
:param maze:
:param cost
:param start:
:param end:
:return:
"""
# Create start and end node with initized values for g, h and f
start_node = Node(None, tuple(start))
start_node.g = start_node.h = start_node.f = 0
end_node = Node(None, tuple(end))
end_node.g = end_node.h = end_node.f = 0
# Initialize both yet_to_visit and visited list
# in this list we will put all node that are yet_to_visit for exploration.
# From here we will find the lowest cost node to expand next
yet_to_visit_list = []
# in this list we will put all node those already explored so that we don't explore it again
visited_list = []
# Add the start node
yet_to_visit_list.append(start_node)
# Adding a stop condition. This is to avoid any infinite loop and stop
# execution after some reasonable number of steps
outer_iterations = 0
max_iterations = (len(maze) // 2) ** 10
# what squares do we search . serarch movement is left-right-top-bottom
#(4 movements) from every positon
move = [[-1, 0 ], # go up
[ 0, -1], # go left
[ 1, 0 ], # go down
[ 0, 1 ]] # go right
"""
1) We first get the current node by comparing all f cost and selecting the lowest cost node for further expansion
2) Check max iteration reached or not . Set a message and stop execution
3) Remove the selected node from yet_to_visit list and add this node to visited list
4) Perofmr Goal test and return the path else perform below steps
5) For selected node find out all children (use move to find children)
a) get the current postion for the selected node (this becomes parent node for the children)
b) check if a valid position exist (boundary will make few nodes invalid)
c) if any node is a wall then ignore that
d) add to valid children node list for the selected parent
For all the children node
a) if child in visited list then ignore it and try next node
b) calculate child node g, h and f values
c) if child in yet_to_visit list then ignore it
d) else move the child to yet_to_visit list
"""
#find maze has got how many rows and columns
no_rows, no_columns = np.shape(maze)
# Loop until you find the end
while len(yet_to_visit_list) > 0:
# Every time any node is referred from yet_to_visit list, counter of limit operation incremented
outer_iterations += 1
# Get the current node
current_node = yet_to_visit_list[0]
current_index = 0
for index, item in enumerate(yet_to_visit_list):
if item.f < current_node.f:
current_node = item
current_index = index
# if we hit this point return the path such as it may be no solution or
# computation cost is too high
if outer_iterations > max_iterations:
print ("giving up on pathfinding too many iterations")
return return_path(current_node,maze)
# Pop current node out off yet_to_visit list, add to visited list
yet_to_visit_list.pop(current_index)
visited_list.append(current_node)
# test if goal is reached or not, if yes then return the path
if current_node == end_node:
return return_path(current_node,maze)
# Generate children from all adjacent squares
children = []
for new_position in move:
# Get node position
node_position = (current_node.position[0] + new_position[0], current_node.position[1] + new_position[1])
# Make sure within range (check if within maze boundary)
if (node_position[0] > (no_rows - 1) or
node_position[0] < 0 or
node_position[1] > (no_columns -1) or
node_position[1] < 0):
continue
# Make sure walkable terrain
if maze[node_position[0]][node_position[1]] != 0:
continue
# Create new node
new_node = Node(current_node, node_position)
# Append
children.append(new_node)
# Loop through children
for child in children:
# Child is on the visited list (search entire visited list)
if len([visited_child for visited_child in visited_list if visited_child == child]) > 0:
continue
# Create the f, g, and h values
child.g = current_node.g + cost
## Heuristic costs calculated here, this is using eucledian distance
child.h = (((child.position[0] - end_node.position[0]) ** 2) +
((child.position[1] - end_node.position[1]) ** 2))
child.f = child.g + child.h
# Child is already in the yet_to_visit list and g cost is already lower
if len([i for i in yet_to_visit_list if child == i and child.g > i.g]) > 0:
continue
# Add the child to the yet_to_visit list
yet_to_visit_list.append(child)
if name == 'main':
maze = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 , 0]]
start =[10, 6] # starting position
end = [14,20] # ending position
cost = 1 # cost per movement
path = search(maze,cost, start, end)
# print(path)
print('\n'.join([''.join(["{:" ">3d}".format(item) for item in row])
for row in path]))

List calculation with elements not equal to zero

Let's assume I have a list:
list1 = [16620, 22032, 0, 0, 0, 136813, 137899, 0, 199546, 204804]
I am looking for a new list that subtracts every 'non-zero' value from the following 'non-zero' value, e.g. 22032-16620, 137899-136813. 'Zero' values will stay untouched.
In addition to that, the subtracted 'non-zero' value should change to zero.
The output would look something like:
list2 = [0, 5412, 0, 0, 0, 0, 1086, 0, 0, 5258]
Please note that the numbers, the length of the list and its distribution of elements may vary, e.g. a list could also look like
list1 = [0, 0, 0, 0, 95472, 0, 0, 104538, 0, 0, 0, 0, 187649, 0, 0, 204841, 0, 0, 0, 0, 0, 0, 0, 0]
which should turn into:
list2 = [0, 0, 0, 0, 0, 0, 0, 9066, 0, 0, 0, 0, 0, 0, 0, 17192, 0, 0, 0, 0, 0, 0, 0, 0]
As you can see, the number of elements stays the same for list1 and list2. Also, there is always an even number of 'zero' values and an even number of 'non-zero' values.
Help is greatly appreciated!
What I have so far:
from itertools import cycle, chain
list1 = [11545, 15334, 71341, 73861, 0, 0, 170374, 171671]
newlist = [list1[i + 1] - list1[i] for i in range(len(list1)-1)]
list2 = list(chain.from_iterable(zip(newlist[0::2], cycle([int()]))))
print list2
The output print list2 looks like I imagine it to be, yet it won't work for a list that looks like:
list1 = [16620, 22032, 0, 0, 0, 136813, 137899, 0, 199546, 204804]
Copy over, but adjust non-zero values, keeping track of the previous one.
list2 = []
prev = None
for curr in list1:
if curr:
if prev:
curr -= prev
prev = None
else:
prev = curr
curr = 0
list2.append(curr)

Fibonacci Adder Machine - Calculating Digits in Fibonacci Sequence

I'm working on a program that will calculate fibonacci numbers with certain digit limitations (i.e. first fibonacci number with 100 digits). The code I have below overall is running, but I am hitting a logical error that has me stumped.
The goal of the code is to calculate Fibonacci numbers in a fashion similar to binary addition. Using an array, each element is to hold a digit from 0 - 9, so each array index represents a 10's place.
It starts working and looping through fine, but it gets off between 13 and 21 because of the way the loop is handled. It adds the number sin the 10's place together and then saves a 31 number.
Is there a way to break out or stop it from adding those together that I'm not seeing?
num1 = [0]*100
num2 = [0]*100
num2[len(num2)-1] = 1
carry = 0
flag = True
while (flag):
#Main for loop to work through the array
for count in range (1, len(num2)):
carry = num2[len(num2) - count] + num1[len(num1) - count]
if carry > 9:
num2[len(num2)- (count + 1)] = num2[len(num2)- (count + 1)] + 1
carry = carry % 10
num1[len(num1) - count] = num2[len(num2) - count]
num2[len(num2) - count] = carry
else:
num1[len(num1) - count] = num2[len(num2) - count]
num2[len(num2) - count] = carry
print(num2)
if num2[0] != 0:
flag = False
Each time it passes the main while loop I'm hoping to see
[0,0,...,0,1]
[0,0,...,0,2]
[0,0,...,0,3]
[0,0,...,0,5]
[0,0,...,0,8]
[0,0,...,1,3]
[0,0,...,2,1]
...
but after it hits the [...,2,1] loop it moves on to [...,3,1]
Here's a bit of a cleaner version of what I believe you're trying to get at.
#Init of Fib variables
a = 0
b = 1
num = 10 #Change this to the number of fib calculation loops.
x = 0
output_arr_len = 100 #Change this to 10 for testing, as it's easier to see.
while x < num:
#Calculate Fib Sequence
c = a + b
a = b
b = c
x += 1
#Output Array
print([0] * (output_arr_len - len(str(c))) + [int(i) for i in str(c)])
Below is the output of the first 20 loops with output_arr_len set to 10.
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 2]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 3]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 5]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 8]
[0, 0, 0, 0, 0, 0, 0, 0, 1, 3]
[0, 0, 0, 0, 0, 0, 0, 0, 2, 1]
[0, 0, 0, 0, 0, 0, 0, 0, 3, 4]
[0, 0, 0, 0, 0, 0, 0, 0, 5, 5]
[0, 0, 0, 0, 0, 0, 0, 0, 8, 9]
[0, 0, 0, 0, 0, 0, 0, 1, 4, 4]
[0, 0, 0, 0, 0, 0, 0, 2, 3, 3]
[0, 0, 0, 0, 0, 0, 0, 3, 7, 7]
[0, 0, 0, 0, 0, 0, 0, 6, 1, 0]
[0, 0, 0, 0, 0, 0, 0, 9, 8, 7]
[0, 0, 0, 0, 0, 0, 1, 5, 9, 7]
[0, 0, 0, 0, 0, 0, 2, 5, 8, 4]
[0, 0, 0, 0, 0, 0, 4, 1, 8, 1]
[0, 0, 0, 0, 0, 0, 6, 7, 6, 5]
[0, 0, 0, 0, 0, 1, 0, 9, 4, 6]
It was even more tricky than in my comments, but this version works correctly:
num1 = [0]*10
num2 = [0]*10
num2[len(num2)-1] = 1
sum = 0
carry = 0
flag = True
while (flag):
#Main for loop to work through the array
for count in range (1, len(num2)):
sum = num2[len(num2) - count] + num1[len(num1) - count] + carry
num1[len(num1) - count] = num2[len(num2) - count]
if sum > 9:
sum = sum % 10
carry = 1
else:
carry = 0
num2[len(num2) - count] = sum
if carry == 1:
num2[0] = num2[0] + 1
print(num2)
if num2[0] != 0:
flag = False
You have also to copy to new1 before applying the carry, even when doing it at the next higher bit...
Here's the corrections to your code. Note that Python has infinite precision integers, so I've added a Fibonacci generator to check the answer.
num1 = [0]*100
num2 = [0]*100
num2[len(num2)-1] = 1
flag = True
# Fibonacci generator for verification of answer
def fib():
a,b = 0,1
while True:
a,b = b,a+b
yield a
# Instance of the generator
f = fib()
# convert a list of single-digit integers to a real integer for display
def value(L):
assert all(n < 10 for n in L) # bug checking for invalid list values.
return int(''.join([str(i) for i in L]))
while (flag):
#Main for loop to work through the array
# Start with zero carry for first digit
carry = 0
for count in range (1,len(num2)+1): # originally off-by-1.
# compute the sum plus the carry of previous sum
temp = num2[len(num2) - count] + num1[len(num1) - count] + carry
# shift num2 digit to num1 digit
num1[len(num1) - count] = num2[len(num2) - count]
# new num2 digit is the one's place of temp sum.
num2[len(num2) - count] = temp % 10
# remember the carry (10's place) for next sum.
carry = temp // 10
# Check for bugs...compare the answer with the next Fibonacci number
assert value(num1) == next(f)
if num1[0] != 0:
flag = False
print(value(num1))
Note you can make the for loop a little simpler by remembering that negative offsets access an array from the end (num2[-1] is the last item in the array) and range can count backwards:
for count in range(-1,-len(num2)-1,-1):
temp = num2[count] + num1[count] + carry
num1[count] = num2[count]
num2[count] = temp % 10
carry = temp // 10 # remember carry for next digit

how to find the frequency of marks each mark from 0 to total marks in a tuple

A teacher is in the process of generating few reports based on the marks scored by the students of her class in a project based assessment.
Assume that the marks of her 10 students are available in a tuple. The marks are out of 25.
Write a python program to implement the following functions:
find_more_than_average(): Find and return the percentage of students who have scored more than the average mark of the class
sort_marks(): Sort the marks in the increasing order from 0 to 25. The sorted values should be populated in a list and returned
generate_frequency(): Find how many students have scored the same marks. For example, how many have scored 0, how many have scored 1, how many have scored 3….how many have scored 25. The result should be populated in a list and returned.
i got the average and sorted parts correct.but for the frequency, if the element is repeated twice i got the frequency as 1
list_of_marks=(12,18,25,24,2,5,18,20,20,21)
def find_more_than_average():
sumi=0
count=0
sumi=sum(list_of_marks)
avg=sumi/len(list_of_marks)
for i in list_of_marks:
if(i>avg):
count=count+1
morethanavg=(count/len(list_of_marks))*100
return morethanavg
#Remove pass and write your logic here
def sort_marks():
return sorted(list_of_marks)
#Remove pass and write your logic here
def generate_frequency():
#Remove pass and write your logic here
gener=[]
for i in range(0,26):
if i in list_of_marks:
gener.append(1)
else:
gener.append(0)
return gener
print(find_more_than_average())
print(generate_frequency())
print(sort_marks())
expected-[0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 2, 1, 0, 0, 1, 1]
actual-[0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1]
When you do:
if i in list_of_marks:
gener.append(1)
else:
gener.append(0)
it should be clear that you can never get a value other than 0 or 1. But you want the counts of those values not just a 1 indicating the value is in the list. One options is to create a list of zeros first, then step through the marks and add one to the index corresponding to the mark:
def generate_frequency():
gener = [0] * 26
for m in list_of_marks:
gener[m] += 1
return gener
Now when you see 20 twice you will increase generator[20] twice with the result:
[0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 2, 1, 0, 0, 1, 1]

Categories