Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 内存中列表的完全外部联接_Sql_Algorithm_Haskell_Full Outer Join - Fatal编程技术网

Sql 内存中列表的完全外部联接

Sql 内存中列表的完全外部联接,sql,algorithm,haskell,full-outer-join,Sql,Algorithm,Haskell,Full Outer Join,如何在具有以下签名的列表上编写类似SQL的完全联接操作 fullJoin::[a]->[b]->(a->b->Bool)->[(可能是a,可能是b)] fullJoin-xs[]z=map(\x->(只有x,没有任何内容))xs fullJoin[]ys\uz=map(\y->(没有,只有y))ys 完全连接xs@(xh:xt)ys@(yh:yt)on= 如果在xh-yh上 然后(只是xh,只是yh):fullJoin xt-yt 其他的 写入的条件由a->b->Bool提供。在本例中,它被设

如何在具有以下签名的列表上编写类似SQL的完全联接操作

fullJoin::[a]->[b]->(a->b->Bool)->[(可能是a,可能是b)]
fullJoin-xs[]z=map(\x->(只有x,没有任何内容))xs
fullJoin[]ys\uz=map(\y->(没有,只有y))ys
完全连接xs@(xh:xt)ys@(yh:yt)on=
如果在xh-yh上
然后(只是xh,只是yh):fullJoin xt-yt
其他的
写入的条件由
a->b->Bool
提供。在本例中,它被设置为
(\n i->length n==i)
,这意味着
名称中的记录与
nums
中的数字具有相同的长度

例如:

names = ["Foo","Bar", "John" , "Emily", "Connor"]
nums = [1,2,3,4,5]

fullJoin names nums (\n i -> length n == i)
  == [ (Just "Foo", Just 3)
     , (Just "Bar", Just 3)
     , (Just "John", Just 4)
     , (Just "Emily", Just 5)
     , (Just "Connor", Nothing)
     , (Nothing, Just 1)
     , (Nothing, Just 2)
     ]
为了澄清上述函数的确切SQL等价物,以下是如何在PostgreSQL中编写该函数:

create table names as
select * from (values 
               ('Foo'),
               ('Bar'),
               ('John'),
               ('Emily'),
               ('Connor')
              ) 
              as z(name);

create table nums as
select * from (values 
               (1),
               (2),
               (3),
               (4),
               (5)
              ) 
              as z(num);

select * from names
full join nums
on char_length(name) = num
运行此操作将产生:

name    num
(null)  1
(null)  2
Foo     3
Bar     3
John    4
Emily   5
Connor  (null)

小提琴链接:

只是无聊地实现你想要它做的事情。超低效:

fullJoin::[a]->[b]->(a->b->Bool)
->[(也许a,也许b)]
fullJoin xs ys p=concatMap(map(Just***Just).snd)a

++[(仅x,无)|(x,[])表
x
Y
之间在条件
rel(x,Y)
下的完全外部连接可以被认为是三个(不相交)部分的并集:

  • 成对的集合
    (x,y)
    其中
    rel(x,y)
  • 对的集合
    (x0,null)
    其中对于y中的所有
    y
    不是(rel(x0,y))
  • 对的集合
    (null,y0)
    其中对于x中的所有
    x
    不是(rel(x,y0))
我们可以用类似的方式构建Haskell计划:

fullJoin::[a]->[b]->(a->b->Bool)->[(可能是a,可能是b)]
fullJoin xs ys rel=concat$

这里是一个简单的Python实现,它是
O(n^2)

这里有一个实现,它与数据库执行连接的方式更为匹配。它是
O(输出的大小)
,通常是
O(n)

对于傻笑和露齿而笑,这两种功能可以结合在一个函数中,这两种功能都是通用的,并且可以运行得很快。(我没有尝试使函数签名合理化,只是试图展示这个想法。)


签名
acc
中的累加器列表参数是否有助于提高性能?不断搜索不断增长的
acc
以查找已经遇到的
xs
如何影响计算复杂性?嗯,我收回它。按照我的想法,你最终会得到
O(I*log(I)*j)
,而我最初的建议是
O(i*j)
(其中
i,j
xs,ys
的长度)。也就是说,我相信有一种方法可以改进我的答案,但不是我当时的想法。我认为你的解决方案比我的更低效。:@FriedBrice天真的方法很简单。其余的方法是围绕边缘进行优化。如果你想更快,你必须按照我的建议做,数据库内部也要做-提取密钥以匹配列表你能解释一下你的答案如何比@FriedBrice的答案更有效吗?我做了两次扫描(
xComments不用于扩展讨论;这段对话已经结束)。
> mapM_ print $ fullJoin names nums (\n i -> length n == i)
(Just "Foo",Just 3)
(Just "Bar",Just 3)
(Just "John",Just 4)
(Just "Emily",Just 5)
(Just "Connor",Nothing)
(Nothing,Just 1)
(Nothing,Just 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))
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