Найти два числа из списка, которые складываются в определенный номер

1

Это супер плохо и грязно, я новичок в этом, пожалуйста, помогите мне.

В основном, я пытался найти два числа из списка, которые составляют целевой номер.

Я установил пример с lst = [2, 4, 6, 10] и целевое значение target = 8. Ответ в этом примере будет (2, 6) и (6, 2).

Ниже мой код, но он длинный и уродливый, и я уверен, что есть лучший способ сделать это. Не могли бы вы посмотреть, как я могу улучшить свой код ниже?

from itertools import product, permutations

numbers = [2, 4, 6, 10]
target_number = 8

two_nums = (list(permutations(numbers, 2)))
print(two_nums)

result1 = (two_nums[0][0] + two_nums[0][1])
result2 = (two_nums[1][0] + two_nums[1][1])
result3 = (two_nums[2][0] + two_nums[2][1])
result4 = (two_nums[3][0] + two_nums[3][1])
result5 = (two_nums[4][0] + two_nums[4][1])
result6 = (two_nums[5][0] + two_nums[5][1])
result7 = (two_nums[6][0] + two_nums[6][1])
result8 = (two_nums[7][0] + two_nums[7][1])
result9 = (two_nums[8][0] + two_nums[8][1])
result10 = (two_nums[9][0] + two_nums[9][1])

my_list = (result1, result2, result3, result4, result5, result6, result7, result8, result9, result10)
print (my_list)

for i in my_list:
  if i == 8:
print ("Here it is:" + str(i))
  • 1
    4 и 4 будет решением в вашем примере?
  • 1
    Разве это не подходит для CodeGolf или Code Review ?
Показать ещё 5 комментариев
Теги:
for-loop
permutation

5 ответов

6
Лучший ответ

Для каждого числа в списке вы можете искать его дополнительный (число, которое при добавлении к предыдущему дало бы требуемую target сумму). Если он существует, получите пару и выйдите, иначе двигайтесь дальше.

Это будет выглядеть следующим образом:

numbers = [2, 4, 6, 10]
target_number = 8

for i, number in enumerate(numbers[:-1]):  # note 1
    complementary = target_number - number
    if complementary in numbers[i+1:]:  # note 2
        print("Solution Found: {} and {}".format(number, complementary))
        break
else:  # note 3
    print("No solutions exist")

который производит:

Solution Found: 2 and 6

Заметки:

  1. Вам не нужно проверять последний номер; если бы была пара, вы бы уже ее нашли к тому времени.
  2. Обратите внимание, что проверка членства (которая является довольно дорогостоящей в списках) оптимизирована, поскольку она учитывает только numbers[i+1:] срезов numbers[i+1:]. Предыдущие номера уже проверены. Положительным побочным эффектом разреза является то, что существование одного из 4 в списке не дает пары для целевого значения 8.
  3. Это отличная настройка для объяснения понятного и часто путающего использования else for -loops. else срабатывает только в том случае, если цикл не был внезапно завершен break.


Если 4 - 4 решение является приемлемым для вас, даже при наличии одного 4 в списке, вы можете изменить следующим образом:

numbers = [2, 4, 6, 10]
target_number = 8

for i, number in enumerate(numbers):
    complementary = target_number - number
    if complementary in numbers[i:]:
        print("Solution Found: {} and {}".format(number, complementary))
        break
else:
    print("No solutions exist")
  • 1
    Это невероятно, позвольте мне занять некоторое время, чтобы поглотить, большое спасибо! и спасибо, что дали мне решение 4-4 тоже.
  • 2
    @moomoochen Получайте удовольствие, и если возникнут вопросы, я буду рад ответить на них. Приветствия.
1

Если вы пытаетесь найти ответ для нескольких целых чисел с длинным списком, который имеет повторяющиеся значения, я бы порекомендовал использовать frozenset. "Проверенный" ответ получит только первый ответ и затем остановится.

import numpy as np
numbers = np.random.randint(0, 100, 1000)
target = 17

def adds_to_target(base_list, target):
    return_list = []
    for i in range(len(base_list)):
        return_list.extend([list((base_list[i], b)) for b in base_list if (base_list[i] + b)==target])
    return set(map(frozenset, return_list))

# sample output
{frozenset({7, 10}),
 frozenset({4, 13}),
 frozenset({8, 9}),
 frozenset({5, 12}),
 frozenset({2, 15}),
 frozenset({3, 14}),
 frozenset({0, 17}),
 frozenset({1, 16}),
 frozenset({6, 11})}

1) В первом цикле for списки, содержащие два целых числа, которые суммируются с целевым значением, добавляются в "return_list", т.е. создается список списков.

2) Затем заморозка вынимает все дубликаты пар.

%timeit adds_to_target(numbers, target_number)
# 312 ms ± 8.86 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
1

Вы можете сделать это в одну строку с пониманием списка, как показано ниже:

from itertools import permutations

numbers = [2, 4, 6, 10]
target_number = 8
two_nums = (list(permutations(numbers, 2)))

result=[i for i in two_nums if i[0]+i[1] == target_number]

[(2,6), (6,2)]

  • 0
    Возможно, это наименее эффективный способ сделать это, требуя O (n ^ 2) дополнительного пространства.
  • 0
    @ StevenW.Klassen Правда! Просто кажется наиболее доступным для новичка в Python
1

Понимание списка будет хорошо работать здесь. Попробуй это:

from itertools import permutations

numbers = [2, 4, 6, 10]
target_number = 8

solutions = [pair for pair in permutations(numbers, 2) if sum(pair) == 8]
print('Solutions:', solutions)

В принципе, это понимание списка рассматривает все пары, которые permutations(numbers, 2) возвращаются, но сохраняют только те, общая сумма которых равна 8.

1

Простейший общий способ сделать это - перебрать ваш список и для каждого элемента перебрать всю оставшуюся часть списка, чтобы увидеть, добавляет ли он до целевого значения. Недостатком этого является операция O (n ^ 2). Я не знаю, с моей точки зрения, если есть более эффективное решение. Я не уверен на 100%, что мой синтаксис верен, но он должен выглядеть примерно так:

done = False
for i, val in enumerate(numbers):
    if val >= target_number:
        continue
    for j, val2 in enumerate(numbers, i+1):
        if val + val2 == target_number:
            print ("Here it is: " + str(i) + "," + str(j))
            done = True
            break
    if done:
        break

Конечно, вы должны создать это как функцию, которая возвращает ваш результат, а не просто его печать. Это устранило бы необходимость в "сделанной" переменной.

  • 0
    Я прокомментирую мое собственное решение, что представленное @kounis немного лучше. Он не более эффективен (он делает то же самое, что и мой код), но он делает это более элегантно и компактно (с точки зрения количества кода). Он также обрабатывает отрицательные числа, а мой нет.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню