根据重新排序的子集对主列表进行重新排序


19

我最近在工作时遇到一个问题,我有两个列表:一个主列表和一个较小的列表,其中包含主列表中项目的子集,可能以不同的顺序排列。我需要对主列表进行重新排序,以使子集中的项目以相同的顺序出现,而不更改列表中未找到的项目的顺序,并尽可能将项目保持在同一位置。好吧,这听起来可能令人困惑,所以我将其分解:

  • 主清单定义了项目的默认顺序。
  • 子集列表定义某些项目的相对顺序。
  • 如果主列表中有两个元素按照子集列表的顺序排列不正确,则应将主列表中较早的项目移到最早的索引,该索引相对于子集列表中的其他项目位于正确的位置。(即紧接在后面的项目之后)

您的任务是实现此重新排序算法。

示例测试用例

Master: [1, 2, 3]
Subset: []
Result: [1, 2, 3]

Master: [9001, 42, 69, 1337, 420]
Subset: [69]
Result: [9001, 42, 69, 1337, 420]

Master: [9001, 42, 69, 1337, 420, 99, 255]
Subset: [69, 9001, 1337]
Result: [42, 69, 9001, 1337, 420, 99, 255]

Master: [1, 2, 3, 4, 5]
Subset: [2, 5]
Result: [1, 2, 3, 4, 5]

Master: [apple, banana, carrot, duck, elephant]
Subset: [duck, apple]
Result: [banana, carrot, duck, apple, elephant]

Master: [Alice, Betty, Carol, Debbie, Elaine, Felicia, Georgia, Helen, Ilene, Julia]
Subset: [Betty, Felicia, Carol, Julia]
Result: [Alice, Betty, Debbie, Elaine, Felicia, Carol, Georgia, Helen, Ilene, Julia]

Master: [snake, lizard, frog, werewolf, vulture, dog, human]
Subset: [snake, werewolf, lizard, human, dog]
Result: [snake, frog, werewolf, lizard, vulture, human, dog]

Master: [Pete, Rob, Jeff, Stan, Chris, Doug, Reggie, Paul, Alex]
Subset: [Jeff, Stan, Pete, Paul]
Result: [Rob, Jeff, Stan, Pete, Chris, Doug, Reggie, Paul, Alex]

Master: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
Subset: [8, 1, 2, 12, 11, 10]
Result: [3, 4, 5, 6, 7, 8, 1, 2, 9, 12, 11, 10]

Master: [lol, rofl, lmao, roflmao, lqtm, smh, jk, wat]
Subset: [wat, lmao, rofl]
Result: [lol, roflmao, lqtm, smh, jk, wat, lmao, rofl]

规则

  • 标准漏洞,yadda yadda,方便的I / O,等等。
  • 即使示例使用数字和字符串,您也只需要支持一种元素类型,无论是整数,字符串还是其他具有明确定义的等式语义的元素,如果使用您的语言方便,还可以包括异构列表。
  • 您可以假定主列表和子集列表均不包含重复项
  • 您可以假定在子列表中找到的所有项目都在主列表中找到
  • 任一列表都可能为空
  • 您至少必须支持最多100个元素的数组。
  • 重新排序可以就地实现,也可以通过创建新列表/数组来实现。

高尔夫快乐!


1
一个很好的,强壮的问题。
约拿

8 1 3 4 5 6 7 2 9 12 11 10倒数第二个有效的解决方案吗?
法师

@Ven否。尽管这符合使子集项保持相同的相对顺序的限制,但我想确保只有一个正确的答案,因此,较早出现的无序项应移至后来出现乱序。
Beefster

为什么有多个正确答案很重要?请将约束添加到挑战规则中。
Ven的

Answers:


4

视网膜0.8.2,51字节

+`(\b(\w+),(\w+)\b.*¶.*\b)\3,(.*\b\2\b)
$1$4,$3
1A`

在线尝试!在第一行中将输入作为子单词的逗号分隔列表,在第二行中将其作为逗号分隔的主单词列表。说明:

(\b(\w+),(\w+)\b.*¶.*\b)\3,(.*\b\2\b)

在主列表中找到第二个单词在第一个单词之前的两个相邻子单词。

$1$4,$3

将第二个单词移到主列表中第一个单词之后。

+`

重复直到没有单词出现乱序。

1A`

删除子词。


4

JavaScript(ES6), 96 89 74  71字节

它开始时是一个笨拙的混乱局面,最终缩小为简洁而优雅的形式。我要感谢.splice()方法在该方法上的卓有成效的协作。;)

将输入作为(master)(subset)。通过更新主列表输出。

m=>s=>s.map(p=x=>m.splice(p,0,...m.splice(i=m.indexOf(x),p>i||!(p=i))))

在线尝试!

怎么样?

一世p

m.splice(p, 0, ...m.splice(i, condition))

1个

  • 一世[ËËËñŤ]
  • p

0

  • 内部.splice()不会删除任何内容并返回一个空数组
  • 结果,外部.splice()接收到undefined作为其第三个参数,并且未插入任何内容

已评论

m => s =>                 // m[] = master list, s[] = subset list
  s.map(                  //
    p =                   // p = position in the master list of the last element from
                          //     the subset list (initialized to a non-numeric value)
    x =>                  // for each element x in the subset list:
    m.splice(             //   insert in the master list:
      p,                  //     at position p
      0,                  //     without removing any element
      ...m.splice(        //     remove from the master list and flatten:
        i = m.indexOf(x), //       i = position of x in the master list
        p > i             //       if p is greater than i, remove x from its current
                          //       position and insert it at position p
        || !(p = i)       //       otherwise, set p to i and don't remove/insert anything
      )                   //     end of inner splice()
    )                     //   end of outer splice()
  )                       // end of map()

1
“我要感谢.splice()方法的作用……” 提示PPCG奥斯卡音乐节…… :)
Chas Brown

更正确地说,外部拼接调用分别接收3或2个参数,这使它做正确的事情。
尼尔

2

Haskell,79个字节

(m:n)#u@(s:t)|m==s=m:n#t|all(/=m)u=m:n#u|(x,_:z)<-span(/=s)n=(x++s:m:z)#u
m#_=m

在线尝试!

(m:n)#u@(s:t)                 -- m: head of master list
                              -- n: tail of master list
                              -- s: head of subset
                              -- t: tail of subset
                              -- u: whole subset
   |m==s                      -- if m==s
        =m:n#t                -- return 'm' and append a recursive call with 'n' and 't'
   |all(/=m)u                 -- if 'm' is not in 'u'
             =m:n#u           -- return 'm' and append a recursive call with 'n' and 'u'
   |                          -- else (note: 's' is element of 'n')
    (x,_:z)<-span(/=s)n       -- split 'n' into a list 'x' before element 's' and
                              -- a list 'z' after element 's' and
       = (x++s:m:z)#u         -- make a recursive call with
                              -- x++s:m:z as the new master list (i.e. 'm' inserted into 'n' after 's') 
                              -- and 'u'
m # _ = m                     -- if either list is emtpy, return the master list

2

红宝石73 68字节

->a,b{0while b.zip(a&b).find{|m,n|m!=n&&a=a[0..a.index(m)]-[n]|a};a}

在线尝试!

怎么样?

  • 之间的交点a,并b包含的所有元素b,但在相同的顺序,我们会发现他们在a
  • 所以,如果我们迭代 b在交叉点上并行,一旦发现差异,就可以重新定位单个元素。
  • 搬迁是通过切割完成的 a在中找到的元素的位置b,然后删除在交集中找到的元素,然后添加a的其余部分来完成的。
  • 从头开始重复,直到中的所有元素b都以正确的顺序排列a

0在做什么0while
约拿(

这只是一个NOP。
GB

为什么需要它?
约拿(

1
由于比较和操作是在单个块中完成的,因此要避免在开始循环之前声明变量。它的意思是:“什么也不做,而操作返回true。”,代码短于“做了手术,而结果是真”
GB


1

Perl 6,40个字节

{*.permutations.first(*.grep(.any)eq$_)}

在线尝试!

匿名代码块,它采用输入法(如)f(subList)(masterList),并查找主列表索引的第一个字典排列,其中子列表中的元素按正确的顺序排列。

直观地讲,第一个满足要求的置换将使正确排序的元素保持原始顺序,同时将不正确放置的元素向前移动所需的最小距离,以使其具有正确的顺序,从而将它们直接放在子集中的前一个元素之后。

说明:

{*                                     } # Anonymous code block that returns a lambda
  .permutations                          # In all permutations of the master list
               .first(                )  # Find the first permutation
                     (*.grep(.any)       # Where the order of the subset
                                  eq$_   # Is the same as the given order


1

果冻,9字节

Œ!iⱮṢƑ¥ƇḢ

在线尝试!测试套件

效率低下,尤其是对于大型主列表。生成所有可能的排列,过滤掉子集顺序错误的排列,然后返回第一个。

说明

Œ!        | Generate all permutations of the master list
      ¥Ƈ  | Filter including only those where...
  iⱮ      |   the index of each sublist item in this permutation...
     Ƒ    |   is...
    Ṣ     |   in order. 
        Ḣ | Finally take the first item

这似乎不符合规则“在主列表中有两个元素根据子集列表乱序的情况下,应将主列表中位于较早位置的项目移到其在列表中的最早索引处。相对于子集列表中其他项目的正确位置。(即紧接在后面的项目之后)”
Beefster

@Beefster它适用于到目前为止我尝试过的那些。我认为排列的顺序是正确的结果。如果有反例,很高兴被证明是错误的。
尼克·肯尼迪

@Beefster我现在尝试了所有示例,除了女性名字和1..12,结果的顺序是正确的。
尼克·肯尼迪

2
@Beefster 我的回答部分解释了为什么这样做
Jo King

1

J,49个字节

[:(<@({:+i.@>:@-/)@i.~C.])^:(>/@i.~)&.>/]|.@;2<\[

在线尝试!

说明

我们将子集作为左arg,将完整输入作为右。

为了清楚起见,我们将通过一个特定的示例来研究代码:

5 2 4 f 1 2 3 4 5

取子集大小为2的带框的中缀:

2 <\ [

生产:

┌───┬───┐
│5 2│2 4│
└───┴───┘

将它们附加到原始输入,然后反转整个过程:

] |.@;

我们得到:

┌───┬───┬─────────┐
│2 4│5 2│1 2 3 4 5│
└───┴───┴─────────┘

解决上述问题成为从右到左的减少。我们只需要找到正确的动词即可插入/项目之间。

约简的每次迭代都将更新最右边的框(正在转换的完整输入),因此它符合由其左侧​​的对表示的排序约束。归约完成后,输入将遵循完整的子集排序。

如果该对的排序与输入中的排序相同,则以下结果将为0,我们将不执行任何操作:

^:(>/@i.~)

否则它的值为1,我们将动词应用到 ^:

   {: + i.@>:@-/)@i.~ C. ]

将左侧项目移到右侧项目的右侧。这种运动只是两个相关元素之间(包括其中)之间所有项目的循环排列

J具有应用这种循环置换的原语:

<cyclic permutation definition> C. ]

动词的其余部分除了选择我们需要循环的索引之外什么也没做:

{: + i.@>:@-/)@i.~

这似乎比应有的更长,但我无法进一步打通这个短语。

最后,我们将结果重新装箱<@并完成。


0

果冻,24字节

i@€MƤFṬœṗƲḊ;JḟF}W€ʋ@¥ṢFị

在线尝试!测试套件

说明

一个以子集为左侧,主列表为右侧参数的二元链接。下面的示例使用9001、42、69、1337、420、99、255作为主文件,使用69、9001、1337作为子集。

i@€                      | Find the index of each subset item in the master list [3, 1, 4]
         Ʋ               | Previous 4 links as a monad
   MƤ                    | Find the index of the maximum for each prefix of this list [1, 1, 3]
     F                   | Flatten (because the previous result are actually each length one lists)
      Ṭ                  | Convert to a boolean list [1,0,1]
       œṗ                | Partition the [3, 1, 4] list before each 1 [[], [3, 1], [4]]
          Ḋ              | Remove the empty first list [[3, 1], [4]]
                    ¥    | Previous two links as a dyad
                  ʋ@     | Previous 4 links as a dyad with reversed arguments
            J            | Sequence along the master list [1, 2, 3, 4, 5, 6, 7]
             ḟF}         | Filter out items in the flattened [3, 1, 4] list
                W€       | Wrap each item as a list [[2], [5], [6], [7]]
           ;             | Concatenate rhis to the [[3, 1], [4]] list
                     Ṣ   | Sort (effectively by first item in each list) [[2], [3, 1], [4], [5], [6], [7]]
                      F  | Flatten
                       ị | Look up in original master list (and implicitly output)

0

C#(Visual C#交互式编译器),118字节

a=>b=>{for(int j;b.Any();)foreach(var e in b.Intersect(a.Take(j=a.IndexOf(b.Dequeue())))){a.Remove(e);a.Insert(j,e);}}

在线尝试!

利用System.Collections.Generic命名空间中的某些类。母版是List<T>,子集是Queue<T>

// a: master
// b: subset
a=>b=>{
  // continue until b is empty
  for(int j;b.Any();)
    // iterate over values that are out of order in a
    // per the head of b using loop variable e
    foreach(var e in
      // the out of order values are determined by
      // intersecting remaining values in b with
      b.Intersect(
        // values in a occurring before the current head of b
        // save the position in a to variable j and remove the head of b
        a.Take(j=a.IndexOf(b.Dequeue()))
      )
    ){
      // push back the out of order element in a
      a.Remove(e);
      a.Insert(j,e);
    }
}
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.