查找多个列表中的元素数量并组合;删除if / else复杂?

时间:2015-05-28 23:22:44

标签: java list

我有一份清单清单:

List<List<String>> someList = new List<List<>>();

列表的最大大小为五个字符串。它类似于下面的内容:

someList.get(0).size(); // 4 elements
someList.get(1).size(); // 1 elements
someList.get(2).size(); // 3 elements
someList.get(3).size(); // 1 elements
...

我正在尝试通过组合上面的一些嵌套列表来设计一种方法来创建一个特定大小的新列表(1-5个元素)。我可以做类似下面的事情(在这个例子中,三个元素):

public List<String> getThree() {
    for (int j = 0; j < someList.size(); j++) {
        //look for nested lists of size 3
        if (someList.get(j).size() == 3) {
            return someList.get(j);
        }
    for (int j = 0; j < someList.size(); j++) {
        //if found nested list of size 2, find one of size 1 to combine
        if (someList.get(j).size() == 2) {
            for (int k = 0; k < someList.size(); k++) {
                if (someList.get(k).size() == 1) {
                    return someList.get(j).add(someList.get(k).get(0));
                }
            }
        }
    for (int j = 0; j < someList.size(); j++) {
        //if found nested list of size 1, find one of size 2 to combine
        if (someList.get(j).size() == 1) {
            for (int l = 0; l < someList.size(); l++) {
                if (someList.get(l).size() == 2) {
                    return someList.get(j).addAll(someList.get(l));
                }
            }
        }
    }
}

如果没有大小为2的子列表,我没有包含循环,找到大小为1的三个,但你可以想象它可以获得多长时间和多么丑陋。顺序是重要的,因此for循环顺序递增(即,我宁愿将subList 1 + 2组合多于2 + 3,1 + 3多于2 + 3等)。

我希望找到一种动态实现它的方法。我只能理解我的当前方法将提供getFive方法是多么难以理解和冗长。我有多个方法(getOne通过getFive),在这个意义上它不需要是动态的,我只想摆脱很多if / else和for循环来降低复杂性并提高可读性。

我应该提到这是与家庭作业有关的,所以我不太想要一个具体的答案,而是在正确的方向上轻推。或许modulo?与剩余人员有关吗?

编辑;澄清并举例:

aList = new List<String>;
aList.add("a");
aList.add("b");
someList.add(aList);
bList = new List<String>;
bList.add("c");
someList.add(bList);
newList = someList.getThree();
//newList.size() == 3
//newList contains "a","b","c"

getThree()方法正在创建一个新列表,其中包含someList子列表中的元素。它不能拆分子列表(即,它不能从2个元素的子列表中取出1个元素),它将整个子列表组合在一起。

3 个答案:

答案 0 :(得分:3)

如果您的目的是继续从连续列表中收集,直到您获得5个元素,请继续添加,然后在列表填满时突破:

public static List<String> fill(List<List<String>> sources, int size) {
    List<String> list = new ArrayList<>();
    for (List<String> source : sources) 
        if (source.size() <= size - list.size()) 
            list.addAll(source);
    return list;
}

如果您想首先使用最大的列表,请将此行添加为方法的第一行:

Collections.sort(sources, (a, b) -> b.size() - a.size());

在java 8中,非常简洁:

public static List<String> fill(List<List<String>> sources, int size) {
    return sources.stream().reduce(new ArrayList<>(), 
      (a, b) -> {if (b.size() <= a.size() - size) a.addAll(b); return a;});
}

并使用最大的第一个mod:

public static List<String> fill(List<List<String>> sources, int size) {
    return sources.stream()
        .sorted((a,b) -> b.size() - a.size())
        .reduce(new ArrayList<>(), (a, b) -> 
            {if (b.size() <= a.size() - size) a.addAll(b); return a;});
}

答案 1 :(得分:1)

由于您声明组合列表的优先级是从左到右。 O(N ^ 2)循环足以处理组合子列表小于或等于您所需的数量。

public static void main(String[] args) throws Exception {
    List<List<String>> someList = new ArrayList() {{
       add(new ArrayList() {{
           add("a1");
           add("a2");
       }});
       add(new ArrayList() {{
           add("b1");
       }});
       add(new ArrayList() {{
           add("c1");
           add("c2");
           add("c3");
       }});
       add(new ArrayList() {{
           add("d1");
       }});
    }};

    combine(someList, 4);

    for(List<String> subList : someList) {
        System.out.println(subList);
    }
}

private static void combine(List<List<String>> someList, int combineAmount) {
    for (int i = 0; i < someList.size(); i++) {
        // Check if the current list already equals or exceeds the combineAmount
        if (someList.get(i).size() >= combineAmount) {
            continue;
        }

        // Add sublists to the current sublists until the size of the current
        // sublist equals or exceeds the combineAmount
        for (int j = i + 1; j < someList.size(); j++) {
            if (someList.get(i).size() + someList.get(j).size() > combineAmount) {
                continue;
            }
            someList.get(i).addAll(someList.get(j));
            someList.remove(j);
            j--;

            // Don't bother checking other sublists if the newly 
            // combined sublists equals or exceeds the combineAmount
            if (someList.get(i).size() >= combineAmount) {
                break;
            }
        }
    }
}

结果(combineAmount = 4):

[a1, a2, b1, d1]
[c1, c2, c3]

结果(combineAmount = 2):

[a1, a2]
[b1, d1]
[c1, c2, c3]

结果(combineAmount = 6):

[a1, a2, b1, c1, c2, c3]
[d1]

答案 2 :(得分:1)

根据我的理解,您希望将列表列表合并为总共5个索引。这样做时,您希望它首先优先考虑左侧。

这是我创建的一个方法来执行此操作。我知道你不想要一个具体的例子,但我认为一个例子可以帮助你理解并帮助那些也有这个问题的人:

private static List<String> getListOf(List<List<String>> someList, int size) {
    List<List<String>> combine = new ArrayList<List<String>>();
    List<List<String>> combinePrev = new ArrayList<List<String>>();
    int value = 0;
    int indexCloseValue = 0;
    int indexClose;
    for(int i = 0; i < someList.size(); i++){//Loops through the lists
        value = someList.get(i).size();
        boolean[] indexAdded = new boolean[someList.size()];//Used to make sure to not add duplicates
        indexAdded[i] = true;
        combine.add(someList.get(i));//add current loop to the combine list.
        do{//A loop to try to add values other than the one of index i to equal size.  This loops multiple times because it may take more than two to equal size.
            indexCloseValue = 0;
            indexClose = -1;
            for(int j = 0; j < someList.size(); j++){
                if(!indexAdded[j]){
                    int listSize = someList.get(j).size();
                    if(value + listSize > indexCloseValue && value + listSize <= size){
                        indexCloseValue = listSize;
                        indexClose = j;
                    }
                }
            }
            if(indexClose == -1){
                break;
            }else{
                combine.add(someList.get(indexClose));
                value+=indexCloseValue;
                indexAdded[indexClose] = true;
            }
        }while(value + indexCloseValue < size);
        int added = 0;
        for(List<String> str : combine){//Check size of combine list
            added+=str.size();
        }
        int addedPrev = 0;
        for(List<String> str : combinePrev){//Check size of combinePrev list
            addedPrev+=str.size();
        }
        if(added > addedPrev && added <= size){
            combinePrev = new ArrayList<List<String>>(combine);//Set combinePrev to combine if it is larger but less than size
        }
        combine = new ArrayList<List<String>>();//Reset combine
    }

    List<String> returnList = new ArrayList<String>();
    for(List<String> list : combinePrev){//converts double list to a single list of strings at length "size".
        for(String str : list){
            returnList.add(str);
        }
    }
    return returnList;      
}

如果此代码有任何问题,或者您在评论中有问题请问我。