Algorithm 代码高尔夫:将多个排序列表合并为单个排序列表

Algorithm 代码高尔夫:将多个排序列表合并为单个排序列表,algorithm,language-agnostic,sorting,merge,code-golf,Algorithm,Language Agnostic,Sorting,Merge,Code Golf,实现一种算法,将任意数量的已排序列表合并为一个已排序列表。目标是创建最小的工作程序,使用您喜欢的任何语言 例如: input: ((1, 4, 7), (2, 5, 8), (3, 6, 9)) output: (1, 2, 3, 4, 5, 6, 7, 8, 9) input: ((1, 10), (), (2, 5, 6, 7)) output: (1, 2, 5, 6, 7, 10) 注意:连接输入列表然后使用语言提供的排序功能的解决方案不符合高尔夫精神,将不被接受: sorted

实现一种算法,将任意数量的已排序列表合并为一个已排序列表。目标是创建最小的工作程序,使用您喜欢的任何语言

例如:

input:  ((1, 4, 7), (2, 5, 8), (3, 6, 9))
output: (1, 2, 3, 4, 5, 6, 7, 8, 9)

input:  ((1, 10), (), (2, 5, 6, 7))
output: (1, 2, 5, 6, 7, 10)
注意:连接输入列表然后使用语言提供的排序功能的解决方案不符合高尔夫精神,将不被接受:

sorted(sum(lists,[])) # cheating: out of bounds!
除此之外,您的算法应该(但不必)快得多

清楚地说明语言、任何缺点和人物数量。仅在计数中包含有意义的字符,但出于艺术/可读性的目的,可以随意在代码中添加空格

为了保持整洁,建议在评论中改进,或者在适当的时候编辑答案,而不是为每个“修订”创建新的答案

编辑:如果我再次提交此问题,我会将“无语言提供排序”规则扩展为“不连接所有列表,然后对结果排序”。现有的条目实际上是非常有趣和紧凑的,所以我不会追溯引入一个他们打破的规则,但是在新的提交中可以自由地使用更严格的规范



灵感来源于Python:113个字符

def m(c,l):
    try:
        c += [l[min((m[0], i) for i,m in enumerate(l) if m)[1]].pop(0)]
        return m(c,l)
    except:
        return c

# called as:
>>> m([], [[1,4], [2,6], [3,5]])
[1, 2, 3, 4, 5, 6]
m l|all null l=[]
   |True=x:(m$a++(xs:b))
 where
   n=filter(not.null)l
   (_,min)=minimum$zip(map head n)[0..]
   (a,((x:xs):b))=splitAt min n
def m(i)
  a=[]
  i.each{|s|s.each{|n|a.insert((a.index(a.select{|j|j>n}.last)||-1)+1,n)}}
  a.reverse
end
l1.merge(l2); // Removes the elements from the argument list, inserts 
              // them into the target list, and orders the new, combined 
              // set of elements in ascending order or in some other 
              // specified order.
let f x=List.sort(List.concat x)
编辑:鉴于在一些地方出现了关于性能的讨论,我要提到的是,我认为这是非常有效的实现,尤其是随着列表的增长。我在10个排序的随机数列表上运行了三个算法:

  • 我的解决方案(合并)
  • 排序(总和(列表,[]))
    (内置)
  • 以不同的方式排序(重新实现)

编辑2:(JFS)

地物的标签:

  • merge\u26
    --
    heapq.merge()
    来自Python2.6stdlib
  • merge\u alabaster
    ——上面的代码(上图中标记为
    merge
  • sort\u builtin
    --
    L=sum(列表,[]);L.排序()
  • 是O(N**2),因此不包括在比较中(所有其他解决方案都是O(N)(对于提供的输入))
输入数据为
[f(N)表示范围(10)]
,其中
f()
为:

max_ = 2**31-1
def f(N):
    L = random.sample(xrange(max_), n)
    L.sort()
    return L
f.__name__ = "sorted_random_%d" % max_
注意:
merge\u alabaster()
不适用于
N>100
,原因是
运行时错误:“超过了最大递归深度”

要获取,请键入:

结论:对于相当大的列表,内置排序显示出近似线性的行为,并且是最快的

重新提交

Python-74个字符(计算空格和换行符)

i
作为列表列表输入

用法:

>>> m([[1,5],[6,3]])
[1, 3, 5, 6]

对于Python,我不认为您能得到比的响应更好的结果

更改为处理您的输入:

import heapq
def m(i): 
    return list(heapq.merge(*i))

print m(((1, 4, 7), (2, 5, 8), (3, 6, 9)))
对于实际功能,59个字符,或简化版本中的52个字符:

import heapq
def m(i): return list(heapq.merge(*i))
这还具有使用Python内置的经过测试的真实实现的好处


编辑:删除了分号(谢谢)。

Haskell:127个字符(没有缩进和换行)

它基本上概括了两个列表的合并

let p l=
    let f a b=List.filter(a b) in
    let rec s=function[]->[]|x::y->s(f(>)x y)@[x]@s(f(<=)x y) in
    [for a in l->>a]|>s
pl=
设f a b=List.filter(ab)in
设rec s=function[]->[]|x::y->s(f(>)xy)@[x]@s(f(>a]|>s
注意:这段代码会导致F#抛出大量警告,但它可以工作:)

以下是带注释的版本,其中包含空格和有意义的标识符(注意:上面的代码不使用#light语法,下面的代码使用):

l=
//使用指定的筛选运算符筛选我的列表
//使用内置的F#函数
//('a->'b->bool)->'a->('b list->'b list)
让过滤器a b=列表。过滤器(a b)
//快速排序算法
//(“列表->”列表)
设rec qsort=函数
| []->[]
|x::y->qsort(filter(>)xy)@[x]@qsort(filter(>a)|>qsort

虽然我没有耐心尝试,但我的一位同事向我展示了一种方法,可以使用0个字符的键来实现这一点-

Ruby:100个字符(1个有效空格,4个有效换行)

人类版本:

def sorted_join(numbers)
  sorted_numbers=[]

  numbers.each do |sub_numbers|
    sub_numbers.each do |number|
      bigger_than_me = sorted_numbers.select { |i| i > number }
      if bigger_than_me.last
        pos = sorted_numbers.index(bigger_than_me.last) + 1
      else
        pos = 0
      end

      sorted_numbers.insert(pos, number)
    end
  end

  sorted_numbers.reverse
end
这一切都可以用
number.flatte.sort

基准:

 a = [[1, 4, 7], [2, 4, 8], [3, 6, 9]]
 n = 50000
 Benchmark.bm do |b|
   b.report { n.times { m(a) } }
   b.report { n.times { a.flatten.sort } }
 end
产生:

      user     system      total        real
 2.940000   0.380000   3.320000 (  7.573263)
 0.380000   0.000000   0.380000 (  0.892291)

所以我的算法执行得很糟糕,是的!

我就把这个留在这里

语言:C,字符数:265

L[99][99];N;n[99];m[99];i;I;b=0;main(char t){while(scanf("%d%c",L[i]+I,&t)+1){++
I;if(t==10){n[i++]=I;I=0;}}if(I)n[i++] = I;N=i;while(b+1){b=-1;for(i=0;i<N;++i){
I=m[i];if(I-n[i])if(b<0||L[i][I]<L[b][m[b]])b=i;}if(b<0)break;printf("%d ",L[b][
m[b]]);++m[b];}puts("");}

在语言标准中,Common Lisp已经有了一个用于通用序列的
merge
函数,但它只适用于两个序列。对于按升序排序的多个数字列表,它可以用于以下函数(97个基本字符)

(卸载m和其他s) (如果不是(cdr s)) (s车) (申请#m (反对)(合并"名单(汽车)(cadr s)" (所有其他解决方案均为O(N)(针对提供的输入))

如果我们让N为输出中的元素数量,k为输入列表的数量,那么就不能比O快(N log k)——假设每个列表都只是一个元素,那么就可以进行基于比O快(N log N)的比较排序

我看到的那些看起来更像是O(N*k)

您可以相当容易地进入O(N log k)时间:只需将列表放入堆中。这是执行I/O高效排序的方法之一(您也可以推广quicksort和heaps/heapsort)

[没有代码,只有注释]

Python,181个字符



这在O(NlgM)时间内运行,其中N是项目的总数,M是列表的数量。

VB通常不是代码高尔夫的首选语言,但这里仍然是

设置-


        Dim m1 As List(Of Integer) = New List(Of Integer)
        Dim m2 As List(Of Integer) = New List(Of Integer)
        Dim m3 As List(Of Integer) = New List(Of Integer)
        Dim m4 As List(Of Integer) = New List(Of Integer)

        m1.Add(1)
        m1.Add(2)
        m1.Add(3)

        m2.Add(4)
        m2.Add(5)
        m2.Add(6)

        m3.Add(7)
        m3.Add(8)
        m3.Add(9)

        Dim m5 As List(Of List(Of Integer)) = New List(Of List(Of Integer))
        m5.Add(m1)
        m5.Add(m2)
        m5.Add(m3)
VB.NET中的一次尝试(无排序)

整个计划-

        Dim rand As New Random
        Dim m1 As List(Of Integer) = New List(Of Integer)
        Dim m2 As List(Of Integer) = New List(Of Integer)
        Dim m3 As List(Of Integer) = New List(Of Integer)
        Dim m4 As List(Of Integer) = New List(Of Integer)
        Dim m5 As List(Of List(Of Integer)) = New List(Of List(Of Integer))
        m5.Add(m1)
        m5.Add(m2)
        m5.Add(m3)

        For Each d As List(Of Integer) In m5
            For i As Integer = 0 To 100000
                d.Add(rand.Next())
            Next
            d.Sort()
        Next

        Dim sw As New Stopwatch
        sw.Start()
        While m5.Count > 0
            Dim idx As Integer = 0
            Dim min As Integer = Integer.MaxValue
            For k As Integer = 0 To m5.Count - 1
                If m5(k)(0) < min Then min = m5(k)(0) : idx = k
            Next
            m4.Add(min) : m5(idx).RemoveAt(0)
            If m5(idx).Count = 0 Then m5.RemoveAt(idx)
        End While
        sw.Stop()

        'Dim sw As New Stopwatch
        'sw.Start()
        'While m5.Count > 0
        '    m5.Sort(AddressOf Comp)
        '    m4.Add(m5(0)(0)) : m5(0).RemoveAt(0)
        '    If m5(0).Count = 0 Then m5.RemoveAt(0)
        'End While
        'sw.Stop()

        Console.WriteLine(sw.Elapsed)
        Console.ReadLine()
Dim rand作为新随机变量
Dim m1作为列表(整数的)=新列表(整数的)
Dim m2作为列表(整数)
(defun m (&rest s)
  (if (not (cdr s))
      (car s)
      (apply #'m
             (cons (merge 'list (car s) (cadr s) #'<)
                   (cddr s)))))
(defun multi-merge (&rest lists)
  (reduce (lambda (a b) (merge 'list a b #'<)) lists))
(defun m(&rest l)(reduce(lambda(a b)(merge 'list a b #'<))l))
from heapq import *
def m(l):
 r=[]
 h=[]
 for x in l:
  if x:
   heappush(h, (x[0], x[1:]))
 while h:
  e,f=heappop(h)
  r.append(e)
  if f:
   heappush(h, (f.pop(0),f))
 return r

        Dim m1 As List(Of Integer) = New List(Of Integer)
        Dim m2 As List(Of Integer) = New List(Of Integer)
        Dim m3 As List(Of Integer) = New List(Of Integer)
        Dim m4 As List(Of Integer) = New List(Of Integer)

        m1.Add(1)
        m1.Add(2)
        m1.Add(3)

        m2.Add(4)
        m2.Add(5)
        m2.Add(6)

        m3.Add(7)
        m3.Add(8)
        m3.Add(9)

        Dim m5 As List(Of List(Of Integer)) = New List(Of List(Of Integer))
        m5.Add(m1)
        m5.Add(m2)
        m5.Add(m3)
        While m5.Count > 0
            Dim idx As Integer = 0
            Dim min As Integer = Integer.MaxValue
            For k As Integer = 0 To m5.Count - 1
                If m5(k)(0) < min Then min = m5(k)(0) : idx = k
            Next
            m4.Add(min) : m5(idx).RemoveAt(0)
            If m5(idx).Count = 0 Then m5.RemoveAt(idx)
        End While

    Private Function Comp(ByVal l1 As List(Of Integer), ByVal l2 As List(Of Integer)) As Integer
        Return l1(0).CompareTo(l2(0))
    End Function
    .
    .
    .
    While m5.Count > 0
        m5.Sort(AddressOf Comp)
        m4.Add(m5(0)(0)) : m5(0).RemoveAt(0)
        If m5(0).Count = 0 Then m5.RemoveAt(0)
    End While
        Dim rand As New Random
        Dim m1 As List(Of Integer) = New List(Of Integer)
        Dim m2 As List(Of Integer) = New List(Of Integer)
        Dim m3 As List(Of Integer) = New List(Of Integer)
        Dim m4 As List(Of Integer) = New List(Of Integer)
        Dim m5 As List(Of List(Of Integer)) = New List(Of List(Of Integer))
        m5.Add(m1)
        m5.Add(m2)
        m5.Add(m3)

        For Each d As List(Of Integer) In m5
            For i As Integer = 0 To 100000
                d.Add(rand.Next())
            Next
            d.Sort()
        Next

        Dim sw As New Stopwatch
        sw.Start()
        While m5.Count > 0
            Dim idx As Integer = 0
            Dim min As Integer = Integer.MaxValue
            For k As Integer = 0 To m5.Count - 1
                If m5(k)(0) < min Then min = m5(k)(0) : idx = k
            Next
            m4.Add(min) : m5(idx).RemoveAt(0)
            If m5(idx).Count = 0 Then m5.RemoveAt(idx)
        End While
        sw.Stop()

        'Dim sw As New Stopwatch
        'sw.Start()
        'While m5.Count > 0
        '    m5.Sort(AddressOf Comp)
        '    m4.Add(m5(0)(0)) : m5(0).RemoveAt(0)
        '    If m5(0).Count = 0 Then m5.RemoveAt(0)
        'End While
        'sw.Stop()

        Console.WriteLine(sw.Elapsed)
        Console.ReadLine()

  def merge_sort(arrs)
    o = Array.new
    arrs.each do |a|
      o = o | a
    end
    o.sort!
  end

  arrs = [ [ 90, 4, -2 ], [ 5, 6, -100 ], [ 5, 7, 2 ] ]
  merge_sort(arrs)
static void f(params int[][] b)
{
    var l = new List<int>();
    foreach(var a in b)l.AddRange(a);
    l.OrderBy(i=>i).ToList().ForEach(Console.WriteLine);
}
static void Main()
{
    f(new int[] { 1, 4, 7 },
      new int[] { 2, 5, 8 },
      new int[] { 3, 6, 9 });
}
sub a{sort map{@$_}@_}
my @sorted = a([1, 2, 3], [5, 6, 89], [13, -1, 3]);
print "@sorted" # prints -1, 1, 1, 2, 3, 3, 5, 6, 89
Sub Main()
    f(New Int32() {1, 4, 7}, _
      New Int32() {2, 5, 8}, _
      New Int32() {3, 6, 9})
End Sub
Sub f(ByVal ParamArray b As Int32()())
    Dim l = New List(Of Int32)
    For Each a In b
        l.AddRange(a)
    Next
    For Each a In l.OrderBy(Function(i) i)
        Console.WriteLine(a)
    Next
End Sub
l1.merge(l2); // Removes the elements from the argument list, inserts 
              // them into the target list, and orders the new, combined 
              // set of elements in ascending order or in some other 
              // specified order.
let f=List.fold_left(List.merge compare)[]
sort -m file1 file2 file3 ...
function merge(a) {
    var r=[], p;
    while(a.length>0) {
        for (var i=0,j=0; i<a.length && p!=a[j][0]; i++)
            if (a[i][0]<a[j][0])
                j = i;

        r.push(p = a[j].shift());

        if (!a[j].length)
            a.splice(j, 1);
    }
    return r;
}
var arr = [[1, 4, 7], [2, 5, 8], [3, 6, 9]]​;
alert(merge(arr));
let f x=List.sort(List.concat x)
let f x=List.sort(Seq.toList(seq{for l in x do yield!l}))
# This merges two lists together
m(){ 
    [[ -z $1 ]] && echo $2 && return; 
    [[ -z $2 ]] && echo $1 && return; 
    A=($1); B=($2); 
    if (( ${A[0]} > ${B[0]} ));then 
        echo -n ${B[0]}\ ;
        unset B[0];
    else 
        echo -n ${A[0]}\ ;
        unset A[0];
    fi;
    m "${A[*]}" "${B[*]}";
}
# This merges multiple lists
M(){
    A=$1;
    shift;
    for x in $@; do
        A=`m "$A" "$x"`
    done
    echo $A
}

$ M '1 4 7' '2 5 8' '3 6 9'
1 2 3 4 5 6 7 8 9
Function s(i)

    s=New List(Of Byte)

    Dim m,c
    Dim N=Nothing

    Do
        m=N
        For Each l In i:
            If l.Count AndAlso(l(0)<m Or m=N)Then m=l(0):c=l

        Next

        If m<>N Then s.Add(m):c.Remove(m)       

    Loop Until m=N

End Function
def f(l):  
 n=[]  
 for t in l:  
  for i in t: n+=[t]  
 s=[]  
 while n: s.+=[min(n)]; n.remove(min(n))  
 return s  
mm = foldl1 m where
  m [] b = b
  m a [] = a
  m (a:as) (b:bs)
   | a <= b = a : m as (b:bs)
   | true   = b : m (a:as) bs