繁体   English   中英

查找数组集中共有的元素集

[英]Finding set of elements common in set of arrays

假设有几个数组:

A. [1,2,3,4,5,6,7,8,9,10]
B. [2,4,6,8,10]
C. [1,4,7,10]
D. [1,3,5,7,9]
.
.

我需要找出所有可能的元素集(1,2,3,4,5 ...),每个元素在至少2个数组(A,B,C ....)中是常见的,并在其中显示如下方式:

(2,4,6,8,10) -> (A,B)
(1,4,7,10) -> (A,C)
(1,3,5,7,9) -> (A,D)
(4,10) -> (A,B,C)
(1,7) -> (A,C,D)

实际输入是包含字符串的文件。 可能有成千上万个文件,每个文件可能包含一百多个密钥字符串。

我尝试了以下方法:首先,我通过比较所有可能的数组对来生成元素集。 然后,我尝试使用逻辑生成其他集合-元素集的相交在数组集的并集中很常见。 像这样:

(2,4,6,8,10) -> (A,B)
(1,4,7,10) -> (A,C)

从上面我们可以得到:

    intersect((2,4,6,8,10),(1,4,7,10)) -> union((A,B),(A,C))
or, (4,10) -> (A,B,C)

还有什么我可以尝试改善时间和内存复杂性的方法-考虑千个输入文件,每个文件包含数百个元素?

我将使用以下方法。

  1. 扫描整个数据以获得在数据中出现的一组元素。
  2. 为每个要素维护一个计数器; 再次扫描数据,并增加每个元素的计数器(如果出现)。
  3. 丢弃所有发生少于2次的元素。
  4. 生成其余元素的所有可能子集。 对于每个子集,如果发生集合中的任何元素,则扫描数据并输出每个数组标识符。

使用哈希图(或地图,如果您需要担心碰撞)。 伪代码如下:

for file in file_list:
   for word in file:
      hash_map[word].append(file)

for wordkey in hash_map:
   print pick_uniques(hash_map[wordkey])

这种方法具有复杂度O(单词总数),而忽略了每个单词的长度。

编辑:由于您还希望将wordkey与相同的pick_uniques(hash_map[wordkey])组合在一起,因此您可以应用相同的hash-map方法,这一次是将键反转。

这个Java类:

public class Store {
Map<Integer,Set<String>> int2keyset = new HashMap<>();
Set<Set<String>> setOfKeyset = new HashSet<>();

public void enter( String key, Integer[] integers ){
    for( Integer val: integers ){
        Set<String> keySet = int2keyset.get( val );
        Set<String> newKeySet = null;
        if( keySet == null ){
            newKeySet = new HashSet<String>();
            newKeySet.add( key );       
        } else {
            newKeySet = new HashSet<>( keySet );
            newKeySet.add( key );
        }
        setOfKeyset.remove( newKeySet );
        setOfKeyset.add( newKeySet );
        int2keyset.put( val, newKeySet );
    }
}

public void dump(){
    Map<Set<String>,Set<Integer>> keySet2intSet = new HashMap<>();
    for( Map.Entry<Integer,Set<String>> entry: int2keyset.entrySet() ){
        Integer intval = entry.getKey();
        Set<String> keySet = entry.getValue();
        Set<Integer> intSet = keySet2intSet.get( keySet );
        if( intSet == null ){
            intSet = new HashSet<Integer>();
        }
        intSet.add( intval );
        keySet2intSet.put( keySet,intSet );
    }
    for( Map.Entry<Set<String>,Set<Integer>> entry: keySet2intSet.entrySet() ){
         System.out.println( entry.getValue() + " => " + entry.getKey() );
}
}
}

当喂入问题中给出的行时,将产生:

[2, 6, 8] => [A, B]
[3, 5, 9] => [A, D]
[4, 10] => [A, B, C]
[1, 7] => [A, C, D]

尽管它与预期输出不完全相同,但它确实包含产生该结果的所有信息,并且更加紧凑。 如果预期会有大量的输入行,那么可能值得追求一种使存储的信息尽可能紧凑的方法,我已经尝试遵循该指南。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM