折叠相邻重复项


22

挑战

给定一个整数列表,请在重复删除所有成对的相邻相等项之后返回这些整数的列表。

请注意,如果您有一个相等的奇数长度游程,则其中一个将保留,而不是成对的一部分。

例:

[0, 0, 0, 1, 2, 4, 4, 2, 1, 1, 0]

首先,你应该删除0, 04, 4以及1, 1获得:

[0, 1, 2, 2, 0]

现在,您应该删除2, 2

[0, 1, 0]

这是最终结果。

测试用例

[]-> []
[1]-> [1]
[1,1]-> []
[1,2]-> [1,2]
[11,11,11]-> [11]
[1,22,1]-> [1,22,1]
[-31,46,-31,46]-> [-31,46,-31,46]
[1、0、0、1]-> []
[5、3、10、10、5]-> [5、3、5]
[5、3、3、3、5]-> [5、3、5]
[0,-2,4,4,-2,0]-> []
[0,2,-14,-14,2,0,-1]-> [-1]
[0,0,0,1,2,4,4,2,1,1,0]-> [0,1,0]
[3、5、4、4、8、26、26、8、5]-> [3]
[-89,89,-87,-8,8,88]-> [-89,89,-87,-8,8,88]

计分

这是,因此每种语言中最短的答案将获胜!


沙盒,那些可以看到已删除帖子的用户
musicman523 '17

没关系,它们都是平等的。这句话的意思是[14, 14, 14]崩溃为[14]
musicman523

对挑战的理解有误,对不起。还以为你已经删除所有对数增加1的(1,211,12,等)
斯蒂芬·

我们可以将输入作为定界字符串吗?
毛茸茸的

2
您可以添加一个测试用例-89,89,-87,-8,-88吗?我的(未发布的)Japt解决方案和Fry的Retina解决方案都在此失败,输出--87,8
毛茸茸的

Answers:


5

果冻,10字节

Œgœ^/€FµÐL

在线尝试!

怎么运行的

Œgœ^/€FµÐL  Main link. Argument: A (array)

       µ    Combine all links to the left into a chain.
Œg              Group all adjacent equal items.
    /€          Reduce each group by...
  œ^                symmetric multiset difference.
                In each step, this maps ([], n) to [n] and ([n], n) to [], so the
                group is left with a single item if its length is odd, and no items
                at all if its length if even.
      F         Flatten the resulting array of singleton and empty arrays.
        ÐL  Apply the chain until the results are no longer unique. Return the last
            unique result.

使用而不是F将使您也支持列表中的列表。
暴民埃里克(Erik the Outgolfer)'17年

不,这里œ^依赖整数到数组的提升。由于1D数组不会提升为2D数组,因此它只能用于数字数组。
丹尼斯,

嘿...我的意思是你可以用ŒgWẎ$œ^/$€ẎµÐL...哦,那太天真了。:P
暴民埃里克(Erik the Outgolfer)

4

视网膜17 15字节

+m`^(.+)¶\1$¶?

在线尝试!

感谢Neil和Martin,节省了2个字节!

用任何数字替换每对数字。此过程一直循环直到没有任何更改。


在发现之前,在Japt中设计了一个相同的解决方案。不幸的是,我们都在输入上失败,例如-89 89 -87 -88 -88output --87
毛茸茸的

1
@Shaggy谢谢,我通过添加边界检查并_用来表示底片来纠正它,这在某些语言中很常见。
FryAmTheEggman'7

此后我发现这也会失败_89 89 _87 _8 _88,输出_89 89 _87 8。抱歉:\
毛茸茸的

@Shaggy不要后悔!感谢您发现问题!我添加了另一个边界检查来解决这种情况。
FryAmTheEggman'7

1
@FryAmTheEggman不确定那是否是Neil的意思,但是您还可以使用m\bs转换为^and $
Martin Ender

3

Mathematica 29个字节

这会反复删除成对的相等的相邻元素,a_,a_直到没有剩余的为止。

#//.{b___,a_,a_,c___}:>{b,c}&

3

Python 2,57字节

r=[]
for x in input():r+=x,;r[-2:]*=r[-2:-1]!=[x]
print r

在线尝试!

通过追加下一个元素来迭代构造输出列表,然后如果追加元素等于前一个元素,则切掉末尾。检查倒数第二个元素r[-2:-1]!=[x]会很尴尬,因为列表的长度可能只有1。


真棒答案,做得很好:)
musicman523 '17

2

果冻,15字节

Œr;ṪḂ$$€x/€FµÐL

在线尝试!

说明

Œr;ṪḂ$$€x/€FµÐL  Main Link
Œr               Run-length encode
  ;              Concatenate (?)
       €         For each element
   ṪḂ$$          Is the last element odd?
          €      For each element    // Non-breaking alternative
        x/       Reduce by repeating // for run-length decode
           F     Flatten
            µ    (New monadic link)
             ÐL  Repeat until results are no longer unique

-1字节归功于英里,并固定为:)


@FryAmTheEggman固定; 谢谢!
HyperNeutrino

我不确定是否抛出错误并把输出留空算作正确的解决方案。您的程序抛出ValueError: not enough values to unpack (expected 2, got 0)测试用例[1,2,2,1]。另请注意,空输出与[]2不同[2]

的13个字节Œr;ṪḂ$$€ŒṙµÐL。为避免错误,请替换为Œṙx/€F因为在给定空列表时游程长度解码会引发错误。要将输出显示为列表,添加ŒṘ将显示它。
英里

@ThePirateBay Jelly对空列表的表示是-空,一项-仅该项以及多项-用方括号和逗号分隔的列表。提交的内容是一个链接(函数),而不是一个完整的程序(很像lambda在Python中)- ÇŒṘ在页脚中看到一个更“正常”的视图位置,以调用最后一个链接(Ç)并打印一个Python表示形式(ŒṘ) 。该错误可能不可接受。
乔纳森·艾伦

@乔纳森·艾伦 好的,我意识到Jelly的列表字符串表示形式是可以接受的。我的第一条评论的要点是要提到当列表为空时抛出该错误。

2

JavaScript(ES6),54 53字节

@ThePirateBay节省了1个字节

f=a=>1/a.find(q=>q==a[++i],i=-2)?f(a,a.splice(i,2)):a

天真的递归解决方案,可能是可改进的。


您可以检查当前元素和上一个元素,而不是当前元素和下一个元素,因此可以替换i=0i=-2i-1i总共为-1个字节。

@ guest44851谢谢,但是...这并不意味着我需要将其更改为i+1?(++尽管之前我只有一分钟的时间,但我也尝试过移动它,但无法弄清楚)
ETHproductions'Jul

您可以看到它正常工作

@ThePirateBay真是的,你是对的!但是如何?
ETHproductions

2

Python 2,73个字节

由于我没有足够的声誉来评论:我只是将@officialaimm的答案更改为使用r!= []而不是len(r)来保存字节。@officialaimm对您来说非常聪明的解决方案!

r=[]                            # create list that will hold final results. A new list is important because it needs to be removable.
for i in input():               
 if r!=[]and r[-1]==i:r.pop()   # Ensure that we have at least 1 char added to the list (r!=[])... or that the last character of our final result isn't the current character being scanned. If that is, well, remove it from the final list because we do not want it anymore
 else:r+=[i]                    # Shorthand for r.append(i). This adds i to the final result
print r

在线尝试!

再次太晚了...为什么我什至还没起来呢?



2

MATL,7个字节

t"Y'oY"

对于某些测试结果为空的测试用例,程序会退出并显示错误,但是无论如何它都会产生正确的(空)输出。

在线尝试!使用非空输出来验证测试用例

说明

t     % Implicit input. Duplicate
"     % For each (i.e. do as many times as input size)
  Y'  %   Run-length encode. Gives array of values and array of run lengths
  o   %   Parity, element-wise. Reduces run-lengths to either 0 or 1
  Y"  %   Run-length decode. Gives array of values appearing 0 or 1 times;
      %   that is, removes pairs of consecutive values
      % Implicit end. Implicit display

考虑输入

0 0 0 1 2 4 4 2 1 1 0

每次迭代都会删除成对的连续对。第一次迭代将数组简化为

0 1 2 2 0

2现在相邻的两个值在初始数组中不相邻。这就是为什么需要第二次迭代的原因:

0 1 0

进一步的迭代将使其保持不变。所需的迭代次数以输入大小为上限。

中间结果为空会导致游程长度解码函数(Y")在当前语言版本中出错;但是输出根据需要是空的。


你能补充一个解释吗?我想了解你如何打败我。:P
丹尼斯

@丹尼斯 我已经忘记了。完成:-)
路易斯·门多

1
嗯,RLE推送了两个数组。这很有用。
丹尼斯

2

x86机器代码(32位保护模式),36字节

52
8B 12
8D 44 91 FC
8B F9
8D 71 04
3B F0
77 10
A7
75 F9
83 EF 04
4A
4A
A5
3B F8
75 FB
97
EB E7
58
89 10
C3

上面的机器代码字节定义了一个函数,该函数将数组作为输入,就地折叠相邻的重复项,并返回到调用方而不返回结果。它遵循__fastcall调用约定,分别在ECXEDX寄存器中传递两个参数。

第一个参数(ECX)是指向32位整数数组中第一个元素的指针(如果数组为空,则可以指向内存中的任何位置)。第二个参数(EDX)是指向包含数组长度的32位整数的指针。

如果需要,该函数将就地修改数组的元素,并更新长度以指示折叠数组的新长度。这是获取输入并返回输出的一种不寻常的方法,但是在汇编语言中您别无选择。与C中一样,数组实际上用语言表示为指向第一个元素的指针和一个length。唯一有点奇怪的是通过引用获取长度,但是如果我们不这样做,将无法缩短数组。该代码可以正常工作,但是输出将包含垃圾,因为调用者不知道在哪里停止从折叠数组中打印元素。

非高尔夫装配助记符:

; void __fastcall CollapseAdjacentDuplicates(int * ptrArray, int * ptrLength);
; ECX = ptrArray              ; ECX = fixed ptr to first element
; EDX = ptrLength
   push  edx                  ; save pointer to the length
   mov   edx, [edx]           ; EDX = actual length of the array
   lea   eax, [ecx+edx*4-4]   ; EAX = fixed ptr to last element 

FindAdjacentPairs:
   mov   edi, ecx             ; EDI = ptr to element A
   lea   esi, [ecx+4]         ; ESI = ptr to element B
FindNext:
   cmp   esi, eax             ; is ptr to element B at end?
   ja    Finished             ; if we've reached the end, we're finished
   cmpsd                      ; compare DWORDs at ESI and EDI, set flags, and increment both by 4
   jne   FindNext             ; keep looping if this is not a pair

; Found an adjacent pair, so remove it from the array.
   sub   edi, 4               ; undo increment of EDI so it points at element A
   dec   edx                  ; decrease length of the array by 2
   dec   edx                  ;  (two 1-byte DECs are shorter than one 3-byte SUB)
RemoveAdjacentPair:
   movsd                      ; move DWORD at ESI to EDI, and increment both by 4
   cmp   edi, eax             ; have we reached the end?
   jne   RemoveAdjacentPair   ; keep going until we've reached the end
   xchg  eax, edi             ; set new end by updating fixed ptr to last element
   jmp   FindAdjacentPairs    ; restart search for adjacent pairs from beginning

Finished:
   pop   eax                  ; retrieve pointer to the length
   mov   [eax], edx           ; update length for caller
   ret

该实现受到我C ++ 11答案的启发,但在汇编中进行了精心重写,以实现尺寸的优化。汇编是一种更好的高尔夫语言。:-)

注意:由于此代码使用字符串指令,因此确实假定方向标志是清除的(DF== 0)。在大多数操作环境中,这是一个合理的假设,因为ABI通常要求DF必须清晰。如果不能保证,则需要在代码顶部插入一个1字节的CLD指令(0xFC)。

如前所述,它也假定为32位保护模式,特别是“平面”存储模型,其中额外的段(ES)与数据段(DS)相同。


1

批处理,133字节

@set s=.
:l
@if "%1"=="%2" (shift/1)else set s=%s% %1
@shift/1
@if not "%1"=="" goto l
@if not "%s:~2%"=="%*" %0%s:~1%
@echo(%*

我将设置为,.因为如果只有重复项,则Batch会感到困惑。我还必须使用,shift/1以便可以%0%s:~1%将参数列表设置为新的数组并循环。


我不得不问...为什么?好的答案...但是为什么呢?
扎卡里

@Zacharý因为在那里。
尼尔

1
@Zacharý在某种程度上讲,使用非高尔夫语言打高尔夫是一个很好的理由,因为这实际上可能很有用。没人会在现实生活中启动Jelly解释器来执行此操作,但是他们可能需要在批处理文件中执行此操作!
科迪·格雷

哦。那讲得通。
扎卡里

1

果冻,12 字节

ŒgṁLḂ$$€ẎµÐL

用于获取和返回数字列表的单子链接。

在线尝试!或查看测试套件

怎么样?

ŒgṁLḂ$$€ẎµÐL - Link: list
         µÐL - perform the chain to the left until no changes occur:
Œg           -   group runs (yield a list of lists of non-zero-length equal runs)
      $€     -   last two links as a monad for €ach run:
     $       -     last two links as a monad:
   L         -       length (of the run)
    Ḃ        -       modulo 2 (1 if odd, 0 if even)
  ṁ          -     mould (the run) like (1 or 0) (yields a list of length 1 or 0 lists)
        Ẏ    -   tighten (make the list of lists into a single list)

ṁLḂ$$€相当于ḣLḂ$$€这相当于ṫḊ¿€3$你可以将其替换ṫḊ¿€3在这里形成一个对子/ nilad对。
暴民埃里克(Erik the Outgolfer)'17年

例如,这不适用于游程长度为4的输入。在while循环的每次迭代中,出队的输入是什么?
乔纳森·艾伦

应该给您留下一个包含0或1个元素的列表。如果len(x)== 1,则返回,[]而len(x)== 0则返回0,均为假值。输入到当然是当前值,并且将具有当前值作为左参数和3右参数。如果len(x)== 4,则它与相同ṫ3ṫ3ṫ5不相关[]
暴民埃里克(Erik the Outgolfer)'17年

我可以看到它应该做什么,但是x在您的描述中确实是当前值吗?试试这个尺寸。
乔纳森·艾伦

老实说,我不知道这是代码还是错误:)
Jonathan Allan


1

05AB1E,15个字节

[γʒgÉ}€нÐγ‚€gË#

在线尝试!

说明

[γʒgÉ}€нÐγ‚€gË#
[               # Start infinite loop
 γ              # Group Array into consecutive equal elements
  ʒgÉ}          # Keep the subarrays with an uneven amount of elements
      €н        # Keep only the first element of each subarray
        Ð       # Triplicate the result on the stack
         γ      # Group the top element into consecutive equal elements
          ‚     # Wrap the top two items of the stack in an array
           €g   # Get the length of each subarray
             Ë# # Break if they are equal
                # Implicit print          

1

05AB1E,13个字节

[DγʒgÉ}€нDŠQ#

在线尝试!

说明:

[DγʒgÉ}€нDŠQ# Implicit input
[             Start infinite loop
 D            Duplicate
  γ           Split into chunks of equal elements
   ʒ  }       Filter by
    g           Length
     É          Odd? (0=falsy 1=truthy)
       €      Foreach command
        н     Head
         D    Duplicate
          Š   Push c, a, b
           Q  Equal? (0=falsy 1=truthy)
            # Break if true (i.e. equal to 1)


1

Python 2中74个70 66字节

  • 感谢@SteamyRoot为4个字节:r而不是len(r)足以检查列表/堆栈的空度。
  • 感谢@ovs 4个字节:如果条件更好 [i]==r[-1:]

Python 2,66字节

r=[]
for i in input():
 if[i]==r[-1:]:r.pop()
 else:r+=[i]
print r

在线尝试!


1
如果我的目的len(r)只是检查列表是否为空,那么您应该可以用just代替它r,我想?
SteamyRoot

哦,是的,谢谢。
Officialaimm


@ovs非常感谢,太棒了!(y)
Officialaimm

1
备用66字节长的版本,尽管只需要三行。
乔纳森·弗雷希

0

Clojure,100字节

#(loop[i % j[]](if(= i j)i(recur(mapcat(fn[p](repeat(mod(count p)2)(last p)))(partition-by + i))i)))

不知道这是否是最短的。


0

Bash,82个字节

cat>b
while cat b>a
perl -pe 's/(\d+) \1( |$)//g' a>b
! diff a b>c
do :
done
cat a

所有这些中可能都有一条出路cat,但我不知道。


0

外壳,10个字节

ωoṁS↑o%2Lg

在线尝试!

说明

ωoṁS↑o%2Lg
ω           Repeat until fixed point
 o          the following two functions:
         g   a) group adjacent elements
  ṁ          b) map over groups and concatenate:
        L     length of group
     o%2      mod 2
   S↑         take that many elements of group

0

PHP,81字节

    function f(&$a){for($i=count($a);--$i;)$a[$i]-$a[$i-1]||array_splice($a,$i-1,2);}

功能,可通过引用调用或在线尝试

空输入失败;插入$i&&$a&&--$i修复之前。


0

V,10个字节

òͨ.«©î±î*

在线尝试!

压缩的正则表达式::%s/\(.\+\)\n\1\n*。可选的换行符使它也可以在文件末尾使用。如果我假设末尾有换行符,那将是8个字节...但是这看起来像是一个拉伸


0

直流84 78字节

[L.ly1-dsy0<A]sA[LtLtS.ly1+sy]sP[dStrdStr!=Pz1<O]sO[0syzdsz1<Oly0<Azlz>M]dsMxf

在线尝试!

为了清楚起见,对其进行了一些无序的拆包:

  • [0syzdsz1<Olydsx0<Alx1+lz>M]dsMxf主宏将M计数器重置y为0,检索堆栈中的项数,将其存储在寄存器中zO如果堆栈中至少有两项,则运行宏。一旦O完成,它加载计数器y并把它拷贝到寄存器x检查,以确保前y为非零(意为堆栈.有数据)。如果是这种情况,它将运行macro A。最后,它检查原始堆栈大小是否大于当前堆栈大小,如果是,则重新运行自身。完成后,将使用打印堆栈f
  • [dStrdStr!=Pz1<O]sOO将堆栈中的前两个项目临时存储到堆栈中t。然后比较前两个项目,P如果不相等则运行宏。最后,它检查堆栈上是否至少有两个项目,如果有,则运行自身。
  • [LtLtS.ly1+sy]sPMacro P从堆栈中取出这两项t,将最上面的一项压入主堆栈,然后将下一项压入堆栈.。然后,它增加counter y
  • [L.ly1-dsy0<A]sAA获取堆栈.并将其转回主堆栈。这样做,递减计数器y直到没有剩余可推动的内容为止。

编辑以作解释,并省去了6个字节,因为我不必要地存储堆栈的大小。


0

C ++ 11,161字节

#include<vector>
#include<algorithm>
using V=std::vector<int>;void f(V&v){V::iterator i;while((i=std::adjacent_find(v.begin(),v.end()))!=v.end())v.erase(i,i+2);}

上面的代码定义了一个函数,该函数f接受一个std::vector<int>by引用,将其修改到适当位置以根据规范折叠相邻的重复项,然后返回。

在线尝试!

在检查字节数之前,我认为这是相当精巧的代码。但是,超过150个字节不是很好!我不是很擅长打高尔夫球,或者C ++并不是很好的高尔夫球语言……

取消高尔夫:

#include <vector>
#include <algorithm>

using V = std::vector<int>;

void f(V& v)
{
   V::iterator i;

   // Use std::adjacent_find to search the entire vector for adjacent duplicate elements.
   // If an adjacent pair is found, this returns an iterator to the first element of the
   // pair so that we can erase it. Otherwise, it returns v.end(), and we stop.
   while ((i=std::adjacent_find(v.begin(), v.end())) != v.end())
   {
        v.erase(i, i+2);   // erase this adjacent pair
   }
}

C ++不是最好的高尔夫语言。很好用std::adjacent_find!我不知道你自己实现了这个功能,如果它会更短,因为你可以删除#include <algorithm>,以及
musicman523

@ musicman523 尽管我使用了一些不同的算法,但我的第一次尝试确实是手工实现的。我正在根据std::unique我的需要调整实施。但是,要完成所有逻辑,需要花费大量代码,当我偶然发现时std::adjacent_find,很明显这是代码大小上的赢家。
科迪·格雷

0

PHP,74字节

function c(&$a){foreach($a as$k=>$v)$a[$k+1]===$v&&array_splice($a,$k,2);}

函数c通过引用来调用reduce数组。 在线尝试

有趣的是,这适用于Php5.6,但不适用于7。





By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.