追加时多维数组的所有值都会更改 - Python
All values of multi-dimensional array change on append - Python
我遇到一个问题,我的“all_possible_cuts”数组在我向其附加另一个剪切时发生了变化。
我的代码中有问题的具体部分是:
def append_to_all_possible_cuts(next_cuts):
"""Appends the next possible way to cut the material to the array \"all_possible_cuts\" """
Order.all_possible_cuts.append(next_cuts[:])
previous_cuts = next_cuts
return(previous_cuts)
...
Print(Order.all_possible_cuts)
输出:[[[19.125, 0], [16.125, 0]], [[19.125, 0], [16.125, 0]], ...[[19.125, 0], [16.125, 0]]]
预期输出:[[19.125, 6], [16.125, 1]], [[19.125, 6], [16.125, 0]], [[19.125, 5], [16.125, 3]],...[[19.125, 0], [16.125, 0]]
我发现有人遇到同样问题的文章,但我尝试了他们的解决方案,但似乎没有帮助。
输入输入 144、2、19、15、16、30
这是我的完整代码:
class Order:
purchase_lines = []
all_possible_cuts = []
def get_order_information():
"""Gathers all the starting bar length and cutting information from the order and sorts from largest cut to smallest cut."""
Order.get_starting_material_length()
Order.get_purchase_lines()
Order.purchase_lines = sorted(Order.purchase_lines, reverse=True)
def get_starting_material_length():
"""Gathers the length of the stock bar for the order. Returns starting lenght of the stock material."""
starting_material_length = int(input("What is the length of the stock (in inches)? "))
Order.starting_material_length = starting_material_length
def get_purchase_lines():
"""Gathers all the cut lengths and the quantities needed for each cut length. Adds a tolerance of 0.125 inches to each cutting length. Appends length + quantity needed to """
tolerance = 0.125
num_of_cut_lengths = int(input("How many different cut lengths are there? "))
for cut_length in range(num_of_cut_lengths):
length = float(input("What is the length of the cut (in inches)? "))
qty = int(input("How many " + str(length) + " in. cuts are needed? "))
Order.purchase_lines.append([(length + tolerance), qty])
def generate_all_possible_cuts():
"""Generates an array of every possible way to cut a single piece of stock material"""
first_possible_cut = Order.generate_first_possible_cut(Order.purchase_lines)
another_cut_possible = Order.determine_if_another_cut_possible(first_possible_cut)
previous_cuts = first_possible_cut
while another_cut_possible:
next_cuts = Order.generate_next_possible_cut(previous_cuts)
previous_cuts = Order.append_to_all_possible_cuts(next_cuts)
another_cut_possible = Order.determine_if_another_cut_possible(previous_cuts)
def generate_first_possible_cut(purchase_lines):
"""Using the cut lengths and quantities need, cutting the most pieces possible out of the stock material, starting with the first cut length entered, until the material has remainder of 0 or all cutting lengths have been attempted."""
possible_cut_length_and_qtys = []
remaining_material_length = Order.starting_material_length
for line in purchase_lines:
possible_cut_length = line[0]
max_qty = line[1]
possible_qty = int(remaining_material_length // possible_cut_length)
if possible_qty >= 0 and remaining_material_length - (possible_cut_length * possible_qty) >= 0:
if possible_qty > max_qty:
possible_cut_length_and_qtys.append([possible_cut_length, max_qty])
remaining_material_length -= possible_cut_length * max_qty
else:
possible_cut_length_and_qtys.append([possible_cut_length, possible_qty])
remaining_material_length -= possible_cut_length * possible_qty
Order.remaining_material_length = remaining_material_length
return(possible_cut_length_and_qtys)
def determine_if_another_cut_possible(previous_cuts):
"""Determines if another cut is possible. Returns True if possible, False if not possible."""
for cut in previous_cuts:
cut_qty = cut[1]
if cut_qty > 0:
return(True)
break
else:
return(False)
def generate_next_possible_cut(previous_cuts):
"""Using the previous counts, generates the next possible cut."""
index_of_lowered_digit, lowered_cuts = Order.lower_smallest_digit_possible(previous_cuts)
Order.increase_remaining_material_length(index_of_lowered_digit)
next_cuts = Order.use_remaining_stock(index_of_lowered_digit, lowered_cuts)
return(next_cuts)
def append_to_all_possible_cuts(next_cuts):
"""Appends the next possible way to cut the material to the array \"all_possible_cuts\" """
Order.all_possible_cuts.append(next_cuts[:])
previous_cuts = next_cuts
return(previous_cuts)
def lower_smallest_digit_possible(previous_cuts):
"""Using the previous counts, generates the next possible cut."""
current_cut_index = len(previous_cuts) - 1
while current_cut_index >= 0:
if previous_cuts[current_cut_index][1] > 0:
previous_cuts[current_cut_index][1] -= 1
break
else:
current_cut_index -= 1
return(current_cut_index, previous_cuts)
def increase_remaining_material_length(index_of_lowered_digit):
"""Using the previous counts, generates the next possible cut."""
Order.remaining_material_length += Order.purchase_lines[index_of_lowered_digit][0]
def use_remaining_stock(index_of_lowered_digit, lowered_cuts):
"""Using the previous counts, generates the next possible cut."""
current_index = index_of_lowered_digit + 1
while current_index < len(lowered_cuts):
if Order.remaining_material_length >= lowered_cuts[current_index][0]:
qty = int(Order.remaining_material_length // lowered_cuts[current_index][0])
lowered_cuts[current_index][1] += qty
Order.remaining_material_length -= lowered_cuts[current_index][0] * qty
current_index += 1
return(lowered_cuts)
Order.get_order_information()
Order.generate_all_possible_cuts()
看起来您正在重用数组(a.k.a。Python 列表),而您打算复制它们。
为了快速证明这一点,我将 return 数组代码中的每个 return 语句更改为 return copy.deepcopy(a)
,其中 a
是数组的名称。更改后的代码随后产生了预期的输出。
完整更改的代码包含在这个答案的底部。
为了帮助解释一般问题,请考虑以下示例代码:
a = [0, 1, 2, 3, 4]
b = [a, a, a, a]
print(b)
a[0] = 123
print(b)
示例代码的输出为:
[[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]]
[[123, 1, 2, 3, 4], [123, 1, 2, 3, 4], [123, 1, 2, 3, 4], [123, 1, 2, 3, 4]]
原因是因为 a
数组从未被复制到 b
。 b
数组仅获得 name a
的 4 个副本,而不是名为 a
的整个数组。更正式地说,这意味着 a
被使用 'by reference'.
完全更改的代码:
import copy
class Order:
purchase_lines = []
all_possible_cuts = []
def get_order_information():
"""Gathers all the starting bar length and cutting information from the order and sorts from largest cut to smallest cut."""
Order.get_starting_material_length()
Order.get_purchase_lines()
Order.purchase_lines = sorted(Order.purchase_lines, reverse=True)
def get_starting_material_length():
"""Gathers the length of the stock bar for the order. Returns starting lenght of the stock material."""
starting_material_length = int(input("What is the length of the stock (in inches)? "))
Order.starting_material_length = starting_material_length
def get_purchase_lines():
"""Gathers all the cut lengths and the quantities needed for each cut length. Adds a tolerance of 0.125 inches to each cutting length. Appends length + quantity needed to """
tolerance = 0.125
num_of_cut_lengths = int(input("How many different cut lengths are there? "))
for cut_length in range(num_of_cut_lengths):
length = float(input("What is the length of the cut (in inches)? "))
qty = int(input("How many " + str(length) + " in. cuts are needed? "))
Order.purchase_lines.append([(length + tolerance), qty])
def generate_all_possible_cuts():
"""Generates an array of every possible way to cut a single piece of stock material"""
first_possible_cut = Order.generate_first_possible_cut(Order.purchase_lines)
another_cut_possible = Order.determine_if_another_cut_possible(first_possible_cut)
previous_cuts = first_possible_cut
while another_cut_possible:
next_cuts = Order.generate_next_possible_cut(previous_cuts)
previous_cuts = Order.append_to_all_possible_cuts(next_cuts)
another_cut_possible = Order.determine_if_another_cut_possible(previous_cuts)
def generate_first_possible_cut(purchase_lines):
"""Using the cut lengths and quantities need, cutting the most pieces possible out of the stock material, starting with the first cut length entered, until the material has remainder of 0 or all cutting lengths have been attempted."""
possible_cut_length_and_qtys = []
remaining_material_length = Order.starting_material_length
for line in purchase_lines:
possible_cut_length = line[0]
max_qty = line[1]
possible_qty = int(remaining_material_length // possible_cut_length)
if possible_qty >= 0 and remaining_material_length - (possible_cut_length * possible_qty) >= 0:
if possible_qty > max_qty:
possible_cut_length_and_qtys.append([possible_cut_length, max_qty])
remaining_material_length -= possible_cut_length * max_qty
else:
possible_cut_length_and_qtys.append([possible_cut_length, possible_qty])
remaining_material_length -= possible_cut_length * possible_qty
Order.remaining_material_length = remaining_material_length
return copy.deepcopy(possible_cut_length_and_qtys)
def determine_if_another_cut_possible(previous_cuts):
"""Determines if another cut is possible. Returns True if possible, False if not possible."""
for cut in previous_cuts:
cut_qty = cut[1]
if cut_qty > 0:
return(True)
break
else:
return(False)
def generate_next_possible_cut(previous_cuts):
"""Using the previous counts, generates the next possible cut."""
index_of_lowered_digit, lowered_cuts = Order.lower_smallest_digit_possible(previous_cuts)
Order.increase_remaining_material_length(index_of_lowered_digit)
next_cuts = Order.use_remaining_stock(index_of_lowered_digit, lowered_cuts)
return copy.deepcopy(next_cuts)
def append_to_all_possible_cuts(next_cuts):
"""Appends the next possible way to cut the material to the array \"all_possible_cuts\" """
Order.all_possible_cuts.append(next_cuts[:])
previous_cuts = next_cuts
return copy.deepcopy(previous_cuts)
def lower_smallest_digit_possible(previous_cuts):
"""Using the previous counts, generates the next possible cut."""
current_cut_index = len(previous_cuts) - 1
while current_cut_index >= 0:
if previous_cuts[current_cut_index][1] > 0:
previous_cuts[current_cut_index][1] -= 1
break
else:
current_cut_index -= 1
return(current_cut_index, copy.deepcopy(previous_cuts))
def increase_remaining_material_length(index_of_lowered_digit):
"""Using the previous counts, generates the next possible cut."""
Order.remaining_material_length += Order.purchase_lines[index_of_lowered_digit][0]
def use_remaining_stock(index_of_lowered_digit, lowered_cuts):
"""Using the previous counts, generates the next possible cut."""
current_index = index_of_lowered_digit + 1
while current_index < len(lowered_cuts):
if Order.remaining_material_length >= lowered_cuts[current_index][0]:
qty = int(Order.remaining_material_length // lowered_cuts[current_index][0])
lowered_cuts[current_index][1] += qty
Order.remaining_material_length -= lowered_cuts[current_index][0] * qty
current_index += 1
return copy.deepcopy(lowered_cuts)
Order.get_order_information()
Order.generate_all_possible_cuts()
print(Order.all_possible_cuts)
# test with: 144, 2, 19, 15, 16, 30
我遇到一个问题,我的“all_possible_cuts”数组在我向其附加另一个剪切时发生了变化。
我的代码中有问题的具体部分是:
def append_to_all_possible_cuts(next_cuts):
"""Appends the next possible way to cut the material to the array \"all_possible_cuts\" """
Order.all_possible_cuts.append(next_cuts[:])
previous_cuts = next_cuts
return(previous_cuts)
...
Print(Order.all_possible_cuts)
输出:[[[19.125, 0], [16.125, 0]], [[19.125, 0], [16.125, 0]], ...[[19.125, 0], [16.125, 0]]]
预期输出:[[19.125, 6], [16.125, 1]], [[19.125, 6], [16.125, 0]], [[19.125, 5], [16.125, 3]],...[[19.125, 0], [16.125, 0]]
我发现有人遇到同样问题的文章,但我尝试了他们的解决方案,但似乎没有帮助。
输入输入 144、2、19、15、16、30
这是我的完整代码:
class Order:
purchase_lines = []
all_possible_cuts = []
def get_order_information():
"""Gathers all the starting bar length and cutting information from the order and sorts from largest cut to smallest cut."""
Order.get_starting_material_length()
Order.get_purchase_lines()
Order.purchase_lines = sorted(Order.purchase_lines, reverse=True)
def get_starting_material_length():
"""Gathers the length of the stock bar for the order. Returns starting lenght of the stock material."""
starting_material_length = int(input("What is the length of the stock (in inches)? "))
Order.starting_material_length = starting_material_length
def get_purchase_lines():
"""Gathers all the cut lengths and the quantities needed for each cut length. Adds a tolerance of 0.125 inches to each cutting length. Appends length + quantity needed to """
tolerance = 0.125
num_of_cut_lengths = int(input("How many different cut lengths are there? "))
for cut_length in range(num_of_cut_lengths):
length = float(input("What is the length of the cut (in inches)? "))
qty = int(input("How many " + str(length) + " in. cuts are needed? "))
Order.purchase_lines.append([(length + tolerance), qty])
def generate_all_possible_cuts():
"""Generates an array of every possible way to cut a single piece of stock material"""
first_possible_cut = Order.generate_first_possible_cut(Order.purchase_lines)
another_cut_possible = Order.determine_if_another_cut_possible(first_possible_cut)
previous_cuts = first_possible_cut
while another_cut_possible:
next_cuts = Order.generate_next_possible_cut(previous_cuts)
previous_cuts = Order.append_to_all_possible_cuts(next_cuts)
another_cut_possible = Order.determine_if_another_cut_possible(previous_cuts)
def generate_first_possible_cut(purchase_lines):
"""Using the cut lengths and quantities need, cutting the most pieces possible out of the stock material, starting with the first cut length entered, until the material has remainder of 0 or all cutting lengths have been attempted."""
possible_cut_length_and_qtys = []
remaining_material_length = Order.starting_material_length
for line in purchase_lines:
possible_cut_length = line[0]
max_qty = line[1]
possible_qty = int(remaining_material_length // possible_cut_length)
if possible_qty >= 0 and remaining_material_length - (possible_cut_length * possible_qty) >= 0:
if possible_qty > max_qty:
possible_cut_length_and_qtys.append([possible_cut_length, max_qty])
remaining_material_length -= possible_cut_length * max_qty
else:
possible_cut_length_and_qtys.append([possible_cut_length, possible_qty])
remaining_material_length -= possible_cut_length * possible_qty
Order.remaining_material_length = remaining_material_length
return(possible_cut_length_and_qtys)
def determine_if_another_cut_possible(previous_cuts):
"""Determines if another cut is possible. Returns True if possible, False if not possible."""
for cut in previous_cuts:
cut_qty = cut[1]
if cut_qty > 0:
return(True)
break
else:
return(False)
def generate_next_possible_cut(previous_cuts):
"""Using the previous counts, generates the next possible cut."""
index_of_lowered_digit, lowered_cuts = Order.lower_smallest_digit_possible(previous_cuts)
Order.increase_remaining_material_length(index_of_lowered_digit)
next_cuts = Order.use_remaining_stock(index_of_lowered_digit, lowered_cuts)
return(next_cuts)
def append_to_all_possible_cuts(next_cuts):
"""Appends the next possible way to cut the material to the array \"all_possible_cuts\" """
Order.all_possible_cuts.append(next_cuts[:])
previous_cuts = next_cuts
return(previous_cuts)
def lower_smallest_digit_possible(previous_cuts):
"""Using the previous counts, generates the next possible cut."""
current_cut_index = len(previous_cuts) - 1
while current_cut_index >= 0:
if previous_cuts[current_cut_index][1] > 0:
previous_cuts[current_cut_index][1] -= 1
break
else:
current_cut_index -= 1
return(current_cut_index, previous_cuts)
def increase_remaining_material_length(index_of_lowered_digit):
"""Using the previous counts, generates the next possible cut."""
Order.remaining_material_length += Order.purchase_lines[index_of_lowered_digit][0]
def use_remaining_stock(index_of_lowered_digit, lowered_cuts):
"""Using the previous counts, generates the next possible cut."""
current_index = index_of_lowered_digit + 1
while current_index < len(lowered_cuts):
if Order.remaining_material_length >= lowered_cuts[current_index][0]:
qty = int(Order.remaining_material_length // lowered_cuts[current_index][0])
lowered_cuts[current_index][1] += qty
Order.remaining_material_length -= lowered_cuts[current_index][0] * qty
current_index += 1
return(lowered_cuts)
Order.get_order_information()
Order.generate_all_possible_cuts()
看起来您正在重用数组(a.k.a。Python 列表),而您打算复制它们。
为了快速证明这一点,我将 return 数组代码中的每个 return 语句更改为 return copy.deepcopy(a)
,其中 a
是数组的名称。更改后的代码随后产生了预期的输出。
完整更改的代码包含在这个答案的底部。
为了帮助解释一般问题,请考虑以下示例代码:
a = [0, 1, 2, 3, 4]
b = [a, a, a, a]
print(b)
a[0] = 123
print(b)
示例代码的输出为:
[[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]]
[[123, 1, 2, 3, 4], [123, 1, 2, 3, 4], [123, 1, 2, 3, 4], [123, 1, 2, 3, 4]]
原因是因为 a
数组从未被复制到 b
。 b
数组仅获得 name a
的 4 个副本,而不是名为 a
的整个数组。更正式地说,这意味着 a
被使用 'by reference'.
完全更改的代码:
import copy
class Order:
purchase_lines = []
all_possible_cuts = []
def get_order_information():
"""Gathers all the starting bar length and cutting information from the order and sorts from largest cut to smallest cut."""
Order.get_starting_material_length()
Order.get_purchase_lines()
Order.purchase_lines = sorted(Order.purchase_lines, reverse=True)
def get_starting_material_length():
"""Gathers the length of the stock bar for the order. Returns starting lenght of the stock material."""
starting_material_length = int(input("What is the length of the stock (in inches)? "))
Order.starting_material_length = starting_material_length
def get_purchase_lines():
"""Gathers all the cut lengths and the quantities needed for each cut length. Adds a tolerance of 0.125 inches to each cutting length. Appends length + quantity needed to """
tolerance = 0.125
num_of_cut_lengths = int(input("How many different cut lengths are there? "))
for cut_length in range(num_of_cut_lengths):
length = float(input("What is the length of the cut (in inches)? "))
qty = int(input("How many " + str(length) + " in. cuts are needed? "))
Order.purchase_lines.append([(length + tolerance), qty])
def generate_all_possible_cuts():
"""Generates an array of every possible way to cut a single piece of stock material"""
first_possible_cut = Order.generate_first_possible_cut(Order.purchase_lines)
another_cut_possible = Order.determine_if_another_cut_possible(first_possible_cut)
previous_cuts = first_possible_cut
while another_cut_possible:
next_cuts = Order.generate_next_possible_cut(previous_cuts)
previous_cuts = Order.append_to_all_possible_cuts(next_cuts)
another_cut_possible = Order.determine_if_another_cut_possible(previous_cuts)
def generate_first_possible_cut(purchase_lines):
"""Using the cut lengths and quantities need, cutting the most pieces possible out of the stock material, starting with the first cut length entered, until the material has remainder of 0 or all cutting lengths have been attempted."""
possible_cut_length_and_qtys = []
remaining_material_length = Order.starting_material_length
for line in purchase_lines:
possible_cut_length = line[0]
max_qty = line[1]
possible_qty = int(remaining_material_length // possible_cut_length)
if possible_qty >= 0 and remaining_material_length - (possible_cut_length * possible_qty) >= 0:
if possible_qty > max_qty:
possible_cut_length_and_qtys.append([possible_cut_length, max_qty])
remaining_material_length -= possible_cut_length * max_qty
else:
possible_cut_length_and_qtys.append([possible_cut_length, possible_qty])
remaining_material_length -= possible_cut_length * possible_qty
Order.remaining_material_length = remaining_material_length
return copy.deepcopy(possible_cut_length_and_qtys)
def determine_if_another_cut_possible(previous_cuts):
"""Determines if another cut is possible. Returns True if possible, False if not possible."""
for cut in previous_cuts:
cut_qty = cut[1]
if cut_qty > 0:
return(True)
break
else:
return(False)
def generate_next_possible_cut(previous_cuts):
"""Using the previous counts, generates the next possible cut."""
index_of_lowered_digit, lowered_cuts = Order.lower_smallest_digit_possible(previous_cuts)
Order.increase_remaining_material_length(index_of_lowered_digit)
next_cuts = Order.use_remaining_stock(index_of_lowered_digit, lowered_cuts)
return copy.deepcopy(next_cuts)
def append_to_all_possible_cuts(next_cuts):
"""Appends the next possible way to cut the material to the array \"all_possible_cuts\" """
Order.all_possible_cuts.append(next_cuts[:])
previous_cuts = next_cuts
return copy.deepcopy(previous_cuts)
def lower_smallest_digit_possible(previous_cuts):
"""Using the previous counts, generates the next possible cut."""
current_cut_index = len(previous_cuts) - 1
while current_cut_index >= 0:
if previous_cuts[current_cut_index][1] > 0:
previous_cuts[current_cut_index][1] -= 1
break
else:
current_cut_index -= 1
return(current_cut_index, copy.deepcopy(previous_cuts))
def increase_remaining_material_length(index_of_lowered_digit):
"""Using the previous counts, generates the next possible cut."""
Order.remaining_material_length += Order.purchase_lines[index_of_lowered_digit][0]
def use_remaining_stock(index_of_lowered_digit, lowered_cuts):
"""Using the previous counts, generates the next possible cut."""
current_index = index_of_lowered_digit + 1
while current_index < len(lowered_cuts):
if Order.remaining_material_length >= lowered_cuts[current_index][0]:
qty = int(Order.remaining_material_length // lowered_cuts[current_index][0])
lowered_cuts[current_index][1] += qty
Order.remaining_material_length -= lowered_cuts[current_index][0] * qty
current_index += 1
return copy.deepcopy(lowered_cuts)
Order.get_order_information()
Order.generate_all_possible_cuts()
print(Order.all_possible_cuts)
# test with: 144, 2, 19, 15, 16, 30