简体   繁体   English

Java:从“ Multimap”中创建“ List”

[英]Java : Creating `List` from `Multimap`

I want to arrange values in Multimap in a ordered List . 我想将Multimap中的值排列在有序List Where in all the key will be at the left side and all the values will be at right side. 所有键的位置都在左侧,所有值都在右侧。 I have used recursion to achieve this. 我已经使用递归来实现这一点。 But for that I have to pass List to that recursive function which returns void but the List gets modified in that function which I don't like, is there any way to improve this? 但是,我必须通过List到返回递归函数void ,但List获取该功能修改,我不喜欢,有没有什么办法来提高呢?

Following is my example code 以下是我的示例代码

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]

Please suggest if there is any nice way with which I will not break any principle of clean code and still get the desired result. 请提出建议,如果有什么不错的方法,我不会破坏任何干净代码的原则,但仍然会得到所需的结果。

Update 更新资料

So if we put a new entry in the map like 因此,如果我们在地图中放置一个新条目,例如

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

then corresponding change in the output would be 那么输出中的相应变化将是

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

All the keys on the left and all the values on the right of the list: 列表左侧的所有键和右侧的所有值:

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());
    }
}

If you don't like that list get's modified inside a method. 如果您不喜欢该列表,请在方法内部进行修改。 Before issuing that method create a copy of that list and pass a copy instead of original. 在发出该方法之前,请创建该列表的副本,然后传递副本而不是原始副本。

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

Recursion is a terrible solution for most problems; 对于大多数问题,递归是一个糟糕的解决方案。 including this one. 包括这个。

Try a non-clown solution (assuming 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);
}

I think in a case like this, using an in-out parameter like list could be justified if it makes the overall process more readable, and/or provides performance advantages (fewer memory allocations). 我认为,在这种情况下,如果使用in-out参数(例如list可以使整个过程更具可读性和/或提供性能优势(减少内存分配),则是合理的。 A 'clean' approach where each getChilds() call returns a fresh list which the caller then combines with the others, comes at the price of additional memory allocations and copies. 一种“干净”的方法,其中每个getChilds()调用都返回一个新列表,然后调用方将其与其他调用方合并,以增加内存分配和复制为代价。

The alternative, if you insist on using streams, could maybe be to use mapTo().reduce() on the stream: let getChilds() return a fresh List, and let reduce() combine them all into one. 如果您坚持使用流,则另一种选择可能是在流上使用mapTo()。reduce():让getChilds()返回一个新鲜的List,并让reduce()将它们全部合并为一个。

Personally, if I were to write getChilds() as a function, I'd write a normal loop here and accumulate the results by hand: 就个人而言,如果我将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;
}

Note: This code is not safe against cycles. 注意:此代码对于循环是不安全的。

But code style aside: @DwB raises the good point that by collapsing the whole map into a single flat list, you lose all information about the actual key->(value...) relations. 但是除了代码风格:@DwB带来了一个好处,即通过将整个地图折叠到一个平面列表中,您会丢失有关实际key->(value ...)关系的所有信息。 The output "[ P8, P6, P4, P5]" can be produced by "P8 -> (P6), P4 -> (P5)", or by "P8 -> (P6, P4, P5)". 输出“ [P8,P6,P4,P5]”可以通过“ P8->(P6),P4->(P5)”或“ P8->(P6,P4,P5)”生成。 The code can be made nicer, but is the result in its current form actually useful? 可以使代码更好,但是以当前形式显示的结果实际上有用吗?

    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));
    }

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

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