Java:从'Multimap`创建`List`

时间:2016-02-24 04:57:48

标签: java recursion code-cleanup

我想在有序的Multimap中安排List中的值。所有键都在左侧,所有值都在右侧。我已经使用递归来实现这一点。但为此我必须将List传递给返回void的递归函数,但List在我不喜欢的函数中被修改,是否有任何改进的方法此?

以下是我的示例代码

private static void getChilds(String col, List<String> list, Multimap<String, String> map) {
        list.add(col);
        Collection<String> String = map.get(col);
        if (!String.isEmpty()) {
            String.stream().forEach(col1 -> getChilds(col1, list, map));
        }
    }

    private static List<String> getList(Multimap<String, String> map) {
        Set<String> strings = map.keySet();
        List<String> list = new ArrayList<>();
        for (String string : strings) {
            if (!map.containsValue(string)) {
                getChilds(string, list, map);
            }
        }
        return list;
    }


    public static void main(String[] args) {
        ArrayListMultimap<String, String> map = ArrayListMultimap.create();
        map.put("P1", "P2");
        map.put("P1", "P3");
        map.put("P1", "P4");
        map.put("P3", "P5");
        map.put("P3", "P6");
        map.put("P7", "P8");
        map.put("P7", "P9");
        System.out.println(getList(map));
    }

Output : [P1, P2, P3, P5, P6, P4, P7, P8, P9]

请建议是否有任何好的方法,我不会违反任何干净的代码原则,仍然可以获得理想的结果。

更新

因此,如果我们在地图中添加一个新条目,如

map.put("P10", "P1");

然后输出的相应变化将是

Output : [P7, P8, P9, P10, P1, P2, P3, P5, P6, P4]

4 个答案:

答案 0 :(得分:0)

左侧的所有键和列表右侧的所有值:

List<String> result = new LinkedList<String>();
for (Entry<String, String> entry : map.entries()) 
{
    if (!result.contains(entry.getValue()))
    {
        result.addLast(entry.getValue());
    }
    if (!result.contains(entry.getKey()))
    {
        result.addFirst(entry.getKey());
    }
}

如果您不喜欢该列表,请在方法内修改。在发布该方法之前,请创建该列表的副本并传递副本而不是原始副本。

List<String> copy = new ArrayList<>(original);

答案 1 :(得分:0)

对于大多数问题,递归是一种可怕的解决方案;包括这个。

尝试非小丑解决方案(假设guava multimap):

Set<String> keySet = multiMap.keySet();
List<String> returnValue = new LinkedList<String>();

for (String currentKey : keySet)
{
    Collection<String> values = multiMap.get(currentKey);
    returnValue.add(currentKey);
    returnValue.addAll(values);
}

答案 2 :(得分:0)

我认为在这种情况下,如果使整个过程更具可读性和/或提供性能优势(更少的内存分配),则使用像list这样的输入输出参数是合理的。一种“干净”的方法,其中每个getChilds()调用返回一个新的列表,然后调用者与其他调用组合,这需要额外的内存分配和副本。

另外,如果你坚持使用流,可能是在流上使用mapTo()。reduce():让getChilds()返回一个新的List,让reduce()将它们全部合并为一个

就个人而言,如果我将getChilds()作为一个函数编写,我会在这里编写一个正常的循环并手动累积结果:

private static List<String> getChilds(String col, Multimap<String, String> map) {
    List<String> list = new ArrayList<>();
    list.add(col);
    Collection<String> values = map.get(col);
    for (String val : values) {
        list.addAll(getChilds(val, map);
    }
    return list;
}

注意:此代码对周期不安全。

但是除了代码风格:@DwB提出了一个好处,即通过将整个地图折叠成单个平面列表,您将丢失有关实际键 - &gt;(值...)关系的所有信息。输出“[P8,P6,P4,P5]”可以由“P8 - >(P6),P4 - >(P5)”或“P8 - >(P6,P4,P5)”产生。 。代码可以更好,但其当前形式的结果实际上有用吗?

答案 3 :(得分:0)

    private static List<String> getChilds(String col, Multimap<String, String> map) {
        List<String> list = new ArrayList<>();
        list.add(col);
        map.get(col).forEach(s->list.addAll(getChilds(s,  map)));
        return list;
    }

    private static List<String> getList(Multimap<String, String> map) {
        Set<String> strings = map.keySet();
        List<String> list = new ArrayList<>();
        for (String string : strings) {
            if (!map.containsValue(string)) {
                list.addAll(getChilds(string, map));
            }
        }
        return list;
    }


    public static void main(String[] args) {
        ArrayListMultimap<String, String> map = ArrayListMultimap.create();
        map.put("P1", "P2");
        map.put("P1", "P3");
        map.put("P1", "P4");
        map.put("P3", "P5");
        map.put("P3", "P6");
        map.put("P7", "P8");
        map.put("P7", "P9");
        map.put("P10", "P1");
        System.out.println(getList(map));
    }