簡體   English   中英

清單比較

[英]List comparison

我在面試中使用了這個問題,我想知道最好的解決方案是什么。

編寫一個包含n個列表的Perl子項,然后返回2 ^ n -1個列表,告訴您哪些項目在哪些列表中; 也就是說,哪些項目僅在第一個列表,第二個列表,第一個和第二個列表以及所有其他列表組合中。 假設n相當小(小於20)。

例如:

list_compare([1, 3], [2, 3]);
  => ([1], [2], [3]);

在這里,第一個結果列表給出了僅在列表1中的所有項目,第二個結果列表給出了僅在列表2中的所有項目,第三個結果列表給出了在兩個列表中的所有項目。

list_compare([1, 3, 5, 7], [2, 3, 6, 7], [4, 5, 6, 7])
  => ([1], [2], [3], [4], [5], [6], [7])

在這里,第一個列表給出了僅在列表1中的所有項目,第二個列表給出了僅在列表2中的所有項目,第三個列表給出了在列表1和2中的所有項目,與第一個示例一樣。 第四個列表給出了僅在列表3中的所有項目,第五個列表給出了僅在列表1和3中的所有項目,第六個列表給出了僅在列表2和3中的所有項目,第七個列表給出了所有項目在所有3個列表中。

我通常會將此問題作為該問題的子集( n = 2)的跟進。

解決辦法是什么?

后續處理:列表中的項目為字符串。 可能有重復項,但是由於它們只是字符串,因此應在輸出中壓縮重復項。 輸出列表中項目的順序無關緊要,列表本身的順序無關緊要。

您給定的解決方案仍可以簡化很多。

在第一個循環中,您可以使用普通加法,因為您只能對單個位進行“或”運算,並且可以通過遍歷索引來縮小$bit的范圍。 在第二循環中,可以從索引中減去1而不是產生一個需要是一種不必要的第0個輸出列表元件shift編斷,以及在哪里不必要地遍歷m * n個倍(m為輸出列表的數目,n是唯一元素的數量),對唯一元素進行迭代將迭代減少到僅n個(在m遠大於n的典型用例中,這是一個巨大的勝利), 並且可以簡化代碼。

sub list_compare {
    my ( @list ) = @_;
    my %dest;

    for my $i ( 0 .. $#list ) {
        my $bit = 2**$i;
        $dest{$_} += $bit for @{ $list[ $i ] };
    }

    my @output_list;

    for my $val ( keys %dest ) {
        push @{ $output_list[ $dest{ $val } - 1 ] }, $val;
    }

    return \@output_list;
}

還請注意,一旦想到了這種方式,就可以借助List :: Part模塊非常簡潔地編寫結果收集過程:

use List::Part;

sub list_compare {
    my ( @list ) = @_;
    my %dest;

    for my $i ( 0 .. $#list ) {
        my $bit = 2**$i;
        $dest{$_} += $bit for @{ $list[ $i ] };
    }

    return [ part { $dest{ $_ } - 1 } keys %dest ];
}

但是請注意list_compare是一個可怕的名字。 part_elems_by_membership這樣的東西會更好。 此外,您的問題Ben Tilly指出的不精確之處需要糾正。

首先,我想指出,nohat的答案根本行不通。 嘗試運行它,然后查看Data :: Dumper中的輸出以進行驗證。

就是說,您的問題並不恰當。 看起來您正在使用集合作為數組。 您希望如何處理重復項? 您想如何處理復雜的數據結構? 您希望元素以什么順序排列? 為簡便起見,我將假定答案是壁球重復,可以對復雜的數據結構進行字符串化,並且順序無關緊要。 在這種情況下,以下是一個完全適當的答案:

sub list_compare {
  my @lists = @_;

  my @answers;
  for my $list (@lists) {
    my %in_list = map {$_=>1} @$list;
    # We have this list.
    my @more_answers = [keys %in_list];
    for my $answer (@answers) {
      push @more_answers, [grep $in_list{$_}, @$answer];
    }
    push @answers, @more_answers;
  }

  return @answers;
}

如果要調整這些假設,則需要調整代碼。 例如,不壓扁復雜的數據結構和不壓扁重復項可以使用以下方法完成:

sub list_compare {
  my @lists = @_;

  my @answers;
  for my $list (@lists) {
    my %in_list = map {$_=>1} @$list;
    # We have this list.
    my @more_answers = [@$list];
    for my $answer (@answers) {
      push @more_answers, [grep $in_list{$_}, @$answer];
    }
    push @answers, @more_answers;
  }

  return @answers;
}

但是,這是使用數據結構的字符串化來檢查一個事物中是否存在另一個事物。 放松這種狀況將需要更多的工作。

這是我的解決方案:

構造一個散列的鍵是在輸入列出了所有的元素的結合,和的值是比特串,其中如果元素存在於列表Ii被設置。 位串是使用按位或構造的。 然后,通過遍歷哈希鍵,將鍵添加到關聯的輸出列表來構造輸出列表。

sub list_compare {
    my (@lists) = @_;
    my %compare;
    my $bit = 1;
    foreach my $list (@lists) {
        $compare{$_} |= $bit foreach @$list;
        $bit *= 2; # shift over one bit
    }


    my @output_lists;
    foreach my $item (keys %compare) {
        push @{ $output_lists[ $compare{$item} - 1 ] }, $item;
    }

    return \@output_lists;

}

更新以包括Aristotle建議的反向輸出列表生成

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM