Вот наивная Python реализация. Это O(n^2)
.
#! /usr/bin/env python
def full_join_cond (list1, list2, condition_fn):
answer = []
for x in list1:
matches = []
for y in list2:
if condition_fn(x, y):
matches.append(y)
if len(matches):
answer.extend([[x, y] for y in matches])
else:
answer.append([x, None])
for y in list2:
matched = False
for x in list1:
if condition_fn(x, y):
matched = True
break
if not matched:
answer.append([None, y])
return answer
names = ["Foo","Bar", "John" , "Emily", "Connor"]
nums = [1,2,3,4,5]
cond = lambda x, y: len(x) == y
print(full_join_cond(names, nums, cond))
А вот реализация, которая более точно соответствует тому, как база данных будет выполнять это объединение. Это O(size_of_output)
, что часто O(n)
.
def list_map_to_dict (l, m):
d = {}
for x in l:
mx = m(x)
if mx in d:
d[mx].append(x)
else:
d[mx] = [x]
return d
def full_join_map (list1, map1, list2, map2):
dict1 = list_map_to_dict(list1, map1)
dict2 = list_map_to_dict(list2, map2)
answer = []
for mx, xs in dict1.iteritems():
if mx in dict2:
for y in dict2[mx]:
answer.extend([[x, y] for x in xs])
dict2.pop(mx)
else:
answer.extend([[x, None] for x in xs])
for my, ys in dict2.iteritems():
answer.extend([[None, y] for y in ys])
return answer
print(full_join_map(names, lambda x: len(x), nums, lambda y: y))
. И для хихиканья и усмешки оба могут быть объединены в функцию, которая является общей и может быстро выполняться. (Я не пытался сделать подпись функции разумной - просто пытаюсь показать идею.)
def full_join (list1, map1, list2, map2, cond=None):
if map1 is None:
map1 = lambda x: None
if map2 is None:
map2 = lambda y: None
if cond is None:
cond = lambda x, y: True
dict1 = list_map_to_dict(list1, map1)
dict2 = list_map_to_dict(list2, map2)
answer = []
for mx, xs in dict1.iteritems():
if mx in dict2:
answer.extend(full_join_cond(xs, dict2[mx], cond))
dict2.pop(mx)
else:
answer.extend([[x, None] for x in xs])
for my, ys in dict2.iteritems():
answer.extend([[None, y] for y in ys])
return answer