Есть список чисел в датафрейме. Из этого списка нужно найти пары чисел a и b, такие чтобы a == -b. Если такие пары есть их нужно дропнуть.
Вопрос собственно в том, как это сделать максимально эффективно?
Условия
a == -b- Необходимо найти и удалить все пары.
- Числа удаляются только папарно.
- Числа корорые уже входят в пару не могут быть частью другой пары. Т.е. для числа
снужно искать другоеdдаже еслис == -bилис == -a - Все равно что происходит с нулями
0 == -0. Можно удалить или оставить, главное чтобы работало быстрее. - Не обязательно, но было бы лучше, если бы растояние по индексу, между парой, было минимальным.
- Порядок чисел не должен поменятся после удаления. Нужно оставить исходные индексы датафрейма.
Текущая реализация
def drop_paired(data:pd.DataFrame, target_column:str):
result = data.copy()
result['index'] = result.index
# Сортируем значения без учета знака
result = result.sort_values([target_column, 'index'], key=abs)
result['drop'] = False
value_a = index_a = np.nan
i = start_i = 0
while i < len(result):
row = result.iloc[i]
# Проверяем не использовано это число в качестве какой либо пары
if(~row['drop']):
# Если значение и индекс первого числа в паре (a) не определены, задаем новые
if(index_a is np.nan):
value_a = row[target_column]
index_a = row['index']
start_i = i
# Если нашли b == -a, ставим пометку на удаление и опустошаем значение и индекс первого числа в паре
elif(row[target_column] == -value_a):
result.loc[row['index'], 'drop'] = True
result.loc[index_a, 'drop'] = True
value_a = index_a = np.nan
# Возвращаемся назад для поисков другой пары среди этих же значений
i = start_i
continue
# Если есть а с более "старшим" индексом, возьмём его, чтобы расстояние между a и b было минимальным
elif(row[target_column] == value_a):
index_a = row['index']
# Если числа не равны по модулю, задаем новые
else:
value_a = row[target_column]
index_a = row['index']
start_i = i
i += 1
result = result[~result['drop']].sort_index()
return result[list(data)]
Результат работы
np.random.seed(0)
df = pd.DataFrame(np.random.randint(-6, 11, 20))
print("До дропа")
display(df.value_counts())
display(df)
print("n--------------nПосле дропа")
display(drop_paired(df, 0).value_counts())
drop_paired(df, 0)
Итого
Алгоритм работает, но меня смущает гавнокодовость данного решения. Как сделать лучше?
Sometimes, while working with Python list, we can have a problem in which we need to extract all the possible pairs that can be performed from integers from list. This kind of problem can occur in many domains such as day-day programming and web development. Let’s discuss certain ways in which this task can be performed.
Input : test_list = [1, 7, 4]
Output : [(1, 7), (1, 4), (7, 4)]Input : test_list = [7, 4]
Output : [(7, 4)]
Method #1 : Using list comprehension + enumerate() This is one of the ways in which this task can be performed. In this, we perform the task of pairing using nested loops in list comprehension recipe, and enumerate() is used to check with the next indices while iteration.
Python3
test_list = [1, 7, 4, 3]
print("The original list : " + str(test_list))
res = [(a, b) for idx, a in enumerate(test_list) for b in test_list[idx + 1:]]
print("All possible pairs : " + str(res))
Output
The original list : [1, 7, 4, 3] All possible pairs : [(1, 7), (1, 4), (1, 3), (7, 4), (7, 3), (4, 3)]
Time complexity: O(n^2), where n is the length of the input list.
Auxiliary space: O(n^2), due to the list comprehension creating a new list of all possible pairs.
Method #2: Using combinations() This is one of the ways in which this task can be performed. In this, we just using inbuilt function for pairing and sending 2 as value for making pairs of size 2.
Python3
from itertools import combinations
test_list = [1, 7, 4, 3]
print("The original list : " + str(test_list))
res = list(combinations(test_list, 2))
print("All possible pairs : " + str(res))
Output :
The original list : [1, 7, 4, 3] All possible pairs : [(1, 7), (1, 4), (1, 3), (7, 4), (7, 3), (4, 3)]
Time Complexity: O(n^2) .
Auxiliary Space: O(n^2).
Method #3: Using nested loops
In this approach, we can use nested loops to iterate through each element in the list and form pairs. We can then append each pair to a new list and return it as the result.
step-by-step approach
- Define a list called test_list containing some integer values.
- Print the original list using the print() function.
- Create an empty list called res. This list will hold all the possible pairs.
- Determine the length of the test_list using the len() function and store it in a variable called n.
- Use a nested loop structure to generate all the possible pairs of elements in the test_list. The outer loop will iterate over the elements in the list starting from the first element, and the inner loop will iterate over the remaining elements in the list starting from the next element.
- In each iteration of the loop, append a tuple containing the current pair of elements to the res list.
- Print the result list using the print() function.
- I hope this helps!
Python3
test_list = [1, 7, 4, 3]
print("The original list : " + str(test_list))
res = []
n = len(test_list)
for i in range(n):
for j in range(i+1, n):
res.append((test_list[i], test_list[j]))
print("All possible pairs : " + str(res))
Output
The original list : [1, 7, 4, 3] All possible pairs : [(1, 7), (1, 4), (1, 3), (7, 4), (7, 3), (4, 3)]
Time complexity: O(n^2), where n is the length of the list.
Auxiliary space: O(n^2), as we need to store all possible pairs in the result list.
METHOD 4:Using recursion
APPROACH:
The program finds all possible pairs of elements in a given list and returns the pairs as a list
ALGORITHM:
- Define a function called “all_pairs” that takes a list as input.
- If the length of the list is less than or equal to 1, return an empty list.
- Create an empty list called “pairs”.
- For each element in the list, except the first element, create a tuple of that element and the first element.
- Append the tuple to the “pairs” list.
- Recursively call the “all_pairs” function with the list starting from the second element.
- Return the concatenation of the “pairs” list and the result of the recursive call to “all_pairs” function.
Python3
def all_pairs(lst):
if len(lst) <= 1:
return []
pairs = [(lst[0], x) for x in lst[1:]]
return pairs + all_pairs(lst[1:])
lst = [1, 7, 4, 3]
pairs = all_pairs(lst)
print("All possible pairs:", pairs)
Output
All possible pairs: [(1, 7), (1, 4), (1, 3), (7, 4), (7, 3), (4, 3)]
Time Complexity:
The time complexity of this algorithm is O(n^2), where n is the length of the input list. This is because for each element in the list, the algorithm has to create a tuple with every other element in the list except itself.
Space Complexity:
The space complexity of this algorithm is O(n^2), where n is the length of the input list. This is because the algorithm creates a list of tuples, each containing two elements, for every pair of elements in the input list.
METHOD 5:Using re module.
APPROACH:
This program uses the re module to extract integers from the given input string, and then generates all possible pairs of those integers using a list comprehension. The pairs are then printed as output.
ALGORITHM:
1.Import the re module.
2.Define the input string.
3.Use re.findall() function to extract all integers from the input string and convert them to a list of integers using a list comprehension.
4.Use nested loops to generate all possible pairs of integers from the list.
5.Store the pairs in a list.
6.Print the list of pairs.
Python3
import re
input_string = "The original list : [1, 7, 4, 3]"
integers = [int(num) for num in re.findall(r'd+', input_string)]
pairs = [(integers[i], integers[j]) for i in range(len(integers))
for j in range(i+1, len(integers))]
print("All possible pairs:", pairs)
Output
All possible pairs: [(1, 7), (1, 4), (1, 3), (7, 4), (7, 3), (4, 3)]
Time complexity: O(n^2)
Auxiliary Space: O(n)
Last Updated :
18 May, 2023
Like Article
Save Article
|
0 / 0 / 0 Регистрация: 13.02.2019 Сообщений: 9 |
|
|
1 |
|
Найти в массиве пару одинаковых элементов, стоящих рядом06.03.2019, 19:49. Показов 13359. Ответов 4
Помогите пожалуйста! Задание по информатике 8 класс! Только можно пожалуйста на уровне школьника
0 |
|
m0nte-cr1st0 1040 / 575 / 242 Регистрация: 15.01.2019 Сообщений: 2,178 Записей в блоге: 1 |
||||
|
06.03.2019, 20:59 |
2 |
|||
|
del Добавлено через 20 минут
1 |
|
IvyMia 0 / 0 / 0 Регистрация: 13.02.2019 Сообщений: 9 |
||||
|
07.03.2019, 18:35 [ТС] |
3 |
|||
|
Что неправильно в коде? Не могу выполнить второе условие(найти одинаковые числа, стоящие рядом)
0 |
|
1040 / 575 / 242 Регистрация: 15.01.2019 Сообщений: 2,178 Записей в блоге: 1 |
|
|
07.03.2019, 18:45 |
4 |
|
IvyMia,
0 |
|
dramatist 8 / 5 / 3 Регистрация: 06.02.2019 Сообщений: 29 |
||||
|
07.03.2019, 20:47 |
5 |
|||
|
IvyMia, мне интересно, зачем вам счётчик. Перед вами ведь не стоит задачи подсчитать количество таких совпадений. А что неправильного конкретно в синтаксисе сказать могу: в 10 строке нужно перебирать элменты в диапазоне длины списка (и отнять от него единицу, чтобы избежать ошибки), то есть:
0 |
Дан несортированный массив целых чисел, найти в нем пару с заданной суммой.
Например,
Input:
nums = [8, 7, 2, 5, 3, 1]
target = 10
Output:
Pair found (8, 2)
or
Pair found (7, 3)
Input:
nums = [5, 2, 6, 8, 1, 9]
target = 12
Output: Pair not found
Потренируйтесь в этой проблеме
Существует несколько методов решения этой проблемы с использованием грубой силы, сортировки и хеширования. Они обсуждаются ниже:
1. Использование грубой силы
Наивное решение состоит в том, чтобы рассматривать каждую пару в заданном массиве и возвращаться, если искомая сумма найдена. Этот подход демонстрируется ниже на C, Java и Python:
C
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
#include <stdio.h> // Наивный метод поиска пары в массиве с заданной суммой void findPair(int nums[], int n, int target) { // рассмотрим каждый элемент, кроме последнего for (int i = 0; i < n — 1; i++) { // начинаем с i-го элемента до последнего элемента for (int j = i + 1; j < n; j++) { // если искомая сумма найдена, выводим ее if (nums[i] + nums[j] == target) { printf(«Pair found (%d, %d)n», nums[i], nums[j]); return; } } } // доходим сюда, если пара не найдена printf(«Pair not found»); } int main(void) { int nums[] = { 8, 7, 2, 5, 3, 1 }; int target = 10; int n = sizeof(nums)/sizeof(nums[0]); findPair(nums, n, target); return 0; } |
Скачать Выполнить код
результат:
Pair found (8, 2)
Java
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
class Main { // Наивный метод поиска пары в массиве с заданной суммой public static void findPair(int[] nums, int target) { // рассмотрим каждый элемент, кроме последнего for (int i = 0; i < nums.length — 1; i++) { // начинаем с i-го элемента до последнего элемента for (int j = i + 1; j < nums.length; j++) { // если искомая сумма найдена, выводим ее if (nums[i] + nums[j] == target) { System.out.printf(«Pair found (%d, %d)», nums[i], nums[j]); return; } } } // доходим сюда, если пара не найдена System.out.println(«Pair not found»); } public static void main (String[] args) { int[] nums = { 8, 7, 2, 5, 3, 1 }; int target = 10; findPair(nums, target); } } |
Скачать Выполнить код
результат:
Pair found (8, 2)
Python
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# Наивный метод поиска пары в списке с заданной суммой def findPair(nums, target): # учитывает каждый элемент, кроме последнего for i in range(len(nums) — 1): # начинается с i-го элемента до последнего элемента for j in range(i + 1, len(nums)): # если искомая сумма найдена, вывести ее if nums[i] + nums[j] == target: print(‘Pair found’, (nums[i], nums[j])) return # В списке нет пары с указанной суммой print(‘Pair not found’) if __name__ == ‘__main__’: nums = [8, 7, 2, 5, 3, 1] target = 10 findPair(nums, target) |
Скачать Выполнить код
результат:
Pair found (8, 2)
Временная сложность приведенного выше решения равна O(n2) и не требует дополнительного места, где n это размер ввода.
2. Использование сортировки
Идея состоит в том, чтобы отсортировать заданный массив в порядке возрастания и поддерживать пространство поиска, сохраняя два индекса (low а также high), который изначально указывает на две конечные точки массива. Затем уменьшите область поиска nums[low…high] на каждой итерации цикла путем сравнения суммы элементов, присутствующих в индексах low а также high с желаемой суммой. Увеличение low если сумма меньше ожидаемой суммы; в противном случае уменьшить high если сумма больше желаемой суммы. Если пара найдена, вернуть ее.
Ниже приведена реализация C++, Java и Python, основанная на идее:
C++
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
#include <iostream> #include <algorithm> using namespace std; // Функция поиска пары в массиве с заданной суммой с помощью сортировки void findPair(int nums[], int n, int target) { // сортируем массив по возрастанию sort(nums, nums + n); // поддерживать два индекса, указывающих на конечные точки массива int low = 0; int high = n — 1; // уменьшаем пространство поиска `nums[low…high]` на каждой итерации цикла // цикл до тех пор, пока пространство поиска не будет исчерпано while (low < high) { // сумма найдена if (nums[low] + nums[high] == target) { cout << «Pair found (« << nums[low] << «, « << nums[high] << «)n»; return; } // увеличиваем `low` индекс, если сумма меньше желаемой суммы; // уменьшаем индекс `high`, если сумма больше желаемой суммы (nums[low] + nums[high] < target)? low++: high—; } // доходим сюда, если пара не найдена cout << «Pair not found»; } int main() { int nums[] = { 8, 7, 2, 5, 3, 1 }; int target = 10; int n = sizeof(nums)/sizeof(nums[0]); findPair(nums, n, target); return 0; } |
Скачать Выполнить код
результат:
Pair found (2, 
Java
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
import java.util.Arrays; class Main { // Функция поиска пары в массиве с заданной суммой с помощью сортировки public static void findPair(int[] nums, int target) { // сортируем массив по возрастанию Arrays.sort(nums); // поддерживать два индекса, указывающих на конечные точки массива int low = 0; int high = nums.length — 1; // уменьшаем пространство поиска `nums[low…high]` на каждой итерации цикла // цикл до тех пор, пока пространство поиска не будет исчерпано while (low < high) { // сумма найдена if (nums[low] + nums[high] == target) { System.out.printf(«Pair found (%d, %d)», nums[low], nums[high]); return; } // увеличиваем `low` индекс, если сумма меньше желаемой суммы; // уменьшаем индекс `high`, если сумма больше желаемой суммы if (nums[low] + nums[high] < target) { low++; } else { high—; } } // доходим сюда, если пара не найдена System.out.println(«Pair not found»); } public static void main (String[] args) { int[] nums = { 8, 7, 2, 5, 3, 1 }; int target = 10; findPair(nums, target); } } |
Скачать Выполнить код
результат:
Pair found (2, 
Python
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# Функция поиска пары в массиве с заданной суммой с помощью сортировки def findPair(nums, target): # сортирует список по возрастанию nums.sort() # поддерживает два индекса, указывающих на конечные точки списка (low, high) = (0, len(nums) — 1) # уменьшает пространство поиска `nums[low…high]` на каждой итерации цикла # Цикл # до тех пор, пока пространство поиска не будет исчерпано while low < high: if nums[low] + nums[high] == target: # Цель # найдена print(‘Pair found’, (nums[low], nums[high])) return # увеличивает `low` индекс, если общая сумма меньше желаемой суммы; # уменьшает `high` индекс, если сумма больше желаемой суммы if nums[low] + nums[high] < target: low = low + 1 else: high = high — 1 # Пара с указанной суммой не существует print(‘Pair not found’) if __name__ == ‘__main__’: nums = [8, 7, 2, 5, 3, 1] target = 10 findPair(nums, target) |
Скачать Выполнить код
результат:
Pair found (2, 
Временная сложность приведенного выше решения равна O(n.log(n)) и не требует дополнительного места.
3. Использование хеширования
Мы можем использовать хеш-таблица решить эту задачу за линейное время. Идея состоит в том, чтобы вставить каждый элемент массива nums[i] в карту. Мы также проверяем, есть ли разница (nums[i], target - nums[i]) уже есть на карте или нет. Если разница видна раньше, напечатайте пару и вернитесь. Алгоритм может быть реализован следующим образом на C++, Java и Python:
C++
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
#include <iostream> #include <unordered_map> using namespace std; // Функция поиска пары в массиве с заданной суммой с использованием хеширования void findPair(int nums[], int n, int target) { // создаем пустую карту unordered_map<int, int> map; // делаем для каждого элемента for (int i = 0; i < n; i++) { // проверяем, существует ли пара (nums[i], target — nums[i]) // если разница была видна раньше, выводим пару if (map.find(target — nums[i]) != map.end()) { cout << «Pair found (« << nums[map[target — nums[i]]] << «, « << nums[i] << «)n»; return; } // сохраняем индекс текущего элемента на карте map[nums[i]] = i; } // доходим сюда, если пара не найдена cout << «Pair not found»; } int main() { int nums[] = { 8, 7, 2, 5, 3, 1 }; int target = 10; int n = sizeof(nums)/sizeof(nums[0]); findPair(nums, n, target); return 0; } |
Скачать Выполнить код
результат:
Pair found (8, 2)
Java
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
import java.util.HashMap; import java.util.Map; class Main { // Функция поиска пары в массиве с заданной суммой с использованием хеширования public static void findPair(int[] nums, int target) { // создаем пустой HashMap Map<Integer, Integer> map = new HashMap<>(); // делаем для каждого элемента for (int i = 0; i < nums.length; i++) { // проверяем, существует ли пара (nums[i], target-nums[i]) // если разница была видна раньше, выводим пару if (map.containsKey(target — nums[i])) { System.out.printf(«Pair found (%d, %d)», nums[map.get(target — nums[i])], nums[i]); return; } // сохраняем индекс текущего элемента на карте map.put(nums[i], i); } // доходим сюда, если пара не найдена System.out.println(«Pair not found»); } public static void main (String[] args) { int[] nums = { 8, 7, 2, 5, 3, 1 }; int target = 10; findPair(nums, target); } } |
Скачать Выполнить код
результат:
Pair found (8, 2)
Python
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# Функция поиска пары в массиве с заданной суммой с использованием хеширования def findPair(nums, target): # создать пустой словарь d = {} # делаем на каждый элемент for i, e in enumerate(nums): # проверяет, существует ли пара (e, target — e) #, если разница была видна раньше, вывести пару if target — e in d: print(‘Pair found’, (nums[d.get(target — e)], nums[i])) return # сохраняет индекс текущего элемента в словаре d[e] = i # В списке нет пары с указанной суммой print(‘Pair not found’) if __name__ == ‘__main__’: nums = [8, 7, 2, 5, 3, 1] target = 10 findPair(nums, target) |
Скачать Выполнить код
результат:
Pair found (8, 2)
Временная сложность приведенного выше решения равна O(n) и требует O(n) дополнительное пространство, где n это размер ввода.
Упражнение: Расширьте решение, чтобы вывести все пары в массиве, имеющие заданную сумму.
Похожие сообщения:
Найти тройку с заданной суммой в массиве
4–Суммированная задача | Четверки с заданной суммой
Найдите пару с заданной суммой в BST
Покажите свой код.
Требуется найти разбиение с наибольшим количеством пар?
Дело в том, что разные разбиения дают разное кол-во пар.
Например, у массива [1, 2, 3, 4] существует два разбиения: {(2, 3)} и {(1, 2), (3, 4)}.
Вот пример решения (сложность O(N*log N)):
def pairs(src):
i = 0
src.sort()
result = list()
while i + 1 < len(src):
if src[i+1] - src[i] == 1:
result.append((src[i], src[i+1]))
src = src[:i] + src[i+2:]
i = max(0, i-1)
else:
i += 1
return result
src1 = [1, 5, 9, 11, 10, 4]
src2 = []
src3 = [1, 5, 2, 9, 1, 1, 4, 2, 2, 2]
print(src1, pairs(src1))
print(src2, pairs(src2))
print(src3, pairs(src3))
ps. Обращаю внимание, что функция меняет список!

