对来自多个列表的元素进行分组

Group elements from multiple lists

我有以下数据结构:

基本上我有一个列表,其中包含其他列表(它们的大小可以是任意的,在我的例子中,所有 4 个列表的大小都是 2)。我必须进行分组,以便将具有相同元素的列表归为一个列表(也许不是最好的表述,但我无法更好地表述)。在我的例子中,结果应该如下: [72, 83, 127][110, 119].

例如,如果第三个子列表包含元素[83, 127, 55, 22],则结果应如下所示:[72, 83, 127, 55, 22][110, 119]。 (所以我必须包括所有子列表元素)。

我怎样才能在 Java 或 Groovy 中做这样的事情?

由于您必须处理整个列表,一个不错的选择是利用 groovy 集合的 inject 方法(添加 println 以显示步骤):

def values = [[72, 83], [72, 127], [83, 127], [110, 119]]

def result = values.inject([], { res, value -> 
    println "res = $res | value = $value"
    def found = res.find {
        if (it.intersect(value)) {
            it.addAll(value - it)
            true
        }
    }

    if (!found) {
        res << value
    }

    res
 })

 println result

 assert [[72, 83, 127], [110, 119]] == result

这样:

res = [] | value = [72, 83]
res = [[72, 83]] | value = [72, 127]
res = [[72, 83, 127]] | value = [83, 127]
res = [[72, 83, 127]] | value = [110, 119]
[[72, 83, 127], [110, 119]]

编辑:上述解决方案在某些情况下效果不佳,即

def values = [[72, 83], [72, 127], [83, 127], [110, 119], [47, 56], [56, 72]]

产量

[[72, 83, 127, 56], [110, 119], [47, 56]]

如果列表已排序,它会产生(我认为这是正确的解决方案)

[[47, 56, 72, 83, 127], [110, 119]]

编辑(2): 解决上一个问题的更好的解决方案(即,一个列表共享元素与多个结果列表):

def values = [[72, 83], [72, 127], [83, 127], [110, 119], [120, 121], [121, 127]]

def result = values.inject([], { res, value -> 
    println "res = $res | value = $value"
    def found = res.findAll { it.intersect(value) }
    println "  -> found = $found"

    if (!found) {
        res << value
    } else {
        res.removeAll(found)
        def merged = found.collect({ it + value as Set }).flatten() as Set
        println "  -> merged = $merged"
        res << merged
    }

    println "  => res = $res"
    res
})

这里是 java 使用地图的实现。首先,我们将 ArrayList 转换为映射,即 key=integerInList + value=NoOfOccurrence。然后我们只搜索地图中的每个元素,如果元素出现超过 1 次,那么我们只需添加到相应的组 (Set)。

public static void find() {
    //Input Data
    ArrayList<List<Integer>> list1 = new ArrayList<>();
    list1.add(Arrays.<Integer>asList(72, 83));
    list1.add(Arrays.<Integer>asList(72, 127));
    list1.add(Arrays.<Integer>asList(83, 127));
    list1.add(Arrays.<Integer>asList(110, 119));

    Map<Integer, Integer> map = new HashMap<>();

    //Convert Input Data to Map
    for (List<Integer> integers : list1) {
        for (Integer integer : integers) {
            int integer1=1;
            if (map.containsKey(integer)) {
                integer1 += map.get(integer);
            }
            map.put(integer, integer1);
        }
    }

    Set<Integer> group1 = new HashSet<>();
    Set<Integer> group2 = new HashSet<>();
    //find and build groups
    for (List<Integer> integers : list1) {
        boolean found = false;
        for (Integer integer : integers) {
            if (map.containsKey(integer)) {
                if (map.get(integer) > 1) {
                    found = true;
                    break;
                }
            }
        }
        if (found) {
            group1.addAll(integers);
        } else {
            group2.addAll(integers);
        }
    }

    System.out.println("group1 = " + group1);
    System.out.println("group2 = " + group2);
}