【问题标题】:Java - resize number of nested listsJava - 调整嵌套列表的数量
【发布时间】:2016-05-11 09:27:00
【问题描述】:

我需要一些代码示例或算法来调整 List<List<Integer>> 的大小,这应该可以在下一个方式中使用:

假设我们有下一个newSizeincomingList(伪代码):

    int newSize = 4;
    List<List<Integer>> incomingList = List(List(1,2,3),List(4,5,6),List(7,8,9);

    List<List<Integer>> result = resizeListOfNestedList(newSize, incomingList)

newSize 整数设置incomingList 的新大小,resizeListOfNestedList 应该返回非奇数的下一个结果(例如 4):

    List(List(1,2),List(3,4),List(5,6),List(7,8)

如果 newSize 是奇数(例如 3),则下一步:

    List(List(1,2),List(3,4,5),List(6,7,8)

newSize 总是大于incomingList.size()

如果有任何建议,我将不胜感激。

更新

google.common.Lists 的帮助下,我已经完成了代码草稿(是的,它闻起来很香),我希望它对某人有所帮助。

在我的情况下,方法接收不同的incomingList.size()s 和newSize 参数,很明显incomingList.size()/newSize 将返回双精度值(例如传入 list.size() = 1000,但我们需要将其“压缩”到 600元素)所以我不能一直使用Lists.partitionexpandList 最好在下一个代码之后调用:

int maxSplitValue = (int) Math.ceil((double) incomingList.size() / newSize);

List<List<Integer>> firstPortionValues = Lists.partition(
      incomingList, maxSplitValue
);//size can be less than required after double to int upper round

if (firstPortionValues.size() < maxSplitValue) {
   List<List<Integer>> expandedList = expandList(firstPortionValues, maxSplitValue)
}

结果:

Incoming list:[[0, 1], [2, 3]] 
New size value: 3
Outcoming list:[[0], [1], [2, 3]]

Incoming list:[[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]]
New size value: 4
Outcoming list:[[0.0], [1.0], [2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]]

代码:

public List<List<Integer>> expandList(List<List<Integer>> incomingList, int newSize) {

        List<List<Integer>> resultList = new ArrayList<>();

        for (int index = 0; index < incomingList.size(); index++) {

            List<Integer> nodeList = incomingList.get(index);

            final int minPortionValue = getMinPortionValue(
                incomingList.size(), resultList.size(), nodeList.size(), index, newSize
            );

            List<List<Integer>> portionResult = splitNodeList(new ArrayList<>(nodeList), minPortionValue);

            resultList.addAll(portionResult);
        }

        return resultList;
    }

    private int getMinPortionValue(int listSize, int resultListSize, int listElementSize, int index, int newSize) {

        if (listElementSize > 1) {

            int maxPortionValue = listElementSize % 2 == 0 ? listElementSize / 2 : --listElementSize;
            boolean isOkUseMaxPortionValue = maxPortionValue + listSize - index + resultListSize <= newSize;

            if (isOkUseMaxPortionValue) {
                return maxPortionValue;
            } else {
                return getMinPortionValue(listSize, resultListSize, listElementSize - 1, index, newSize);
            }
        } else {
            return 0;
        }
    }

    private List<List<Integer>> splitNodeList(List<Integer> nodeList, int minSplitValue) {

        List<List<Integer>> result = new ArrayList<>();

        if (minSplitValue > 0) {

            result.addAll(Lists.partition(nodeList, minSplitValue));

            return result;
        } else {

            result.add(nodeList);

            return result;
        }
    }

【问题讨论】:

  • 请向我们展示您到目前为止所做的尝试。
  • @eltabo 如果我有一些有用的代码草案,我会带着问题发布它。请注意,我没有要求完整的解决方案。另外,我想应该有一些 java 库可以提供帮助。
  • 任务不够清晰,例子中你不是丢了9的值吗?
  • 当您谈论处理列表列表时......这基本上是tree,您可能希望相应地实现您的数据结构。它可以为您节省很多头痛。然后这变成了一个更常见的树遍历/重新平衡问题。
  • @unpc 你应该发布一个答案并将你的问题标记为已解决

标签: java nested-lists


【解决方案1】:

您可以编写代码,纯 Java7。此代码保持新列表平衡,最后添加额外元素。

public List<List<Integer>> resizeListOfNestedList(int newSize, List<List<Integer>> data) {

    ArrayList<Integer> allElements = new ArrayList<>();

    for (List<Integer> integers : data) {
        allElements.addAll(integers);
    }

    int elementsPerItem = allElements.size() / newSize;
    int extraElements  = allElements.size() % newSize;
    int indexToStartAddExtraElement = newSize - extraElements;

    ArrayList<List<Integer>> result = new ArrayList<>(newSize);
    Iterator<Integer> iterator = allElements.iterator();

    for (int i = 0; i < newSize; i++){

        int currentItemElementsCount = elementsPerItem;

        if (i >= indexToStartAddExtraElement)
            currentItemElementsCount++;

        ArrayList<Integer> current = new ArrayList<>(currentItemElementsCount);

        for (int j = 0; j < currentItemElementsCount; j++){
            current.add(iterator.next());
        }

        result.add(current);
    }

    return result;
}

【讨论】:

    【解决方案2】:

    为什么你不使用 ListUtils.union(list1,list2);Apache Commons

    Java: how can I split an ArrayList in multiple small ArrayLists?

    【讨论】:

    • 感谢您的回复。就我而言,我不知道块大小。例如,方法接收数组大小 1000 并要求嵌套列表大小应为 600 个元素。如果你尝试计算块,你会得到双倍的1,66,它不能传递给partition(List&lt;T&gt; list, int size)。这就是为什么我将块四舍五入到上限值,划分,然后扩展到所需的大小。
    【解决方案3】:

    看了你的问题,我可以想出两步的算法思路:

    1. 将所有子列表合并为一个列表(使用Guava Iterables
    2. 对步骤 1 的结果进行分区(使用 Guava partition

    Guava 帮助我们更多地关注我们需要什么而不是如何去做,因此很容易翻译您的伪代码和工作代码。

    所以,你可以有这样的东西:

    @Test
    public void test(){
        // Init lists
        List<Integer> a = Lists.newArrayList(1,2,3);
        List<Integer> b = Lists.newArrayList(4,5,6);
        List<Integer> c = Lists.newArrayList(7,8,9);
    
        List<List<Integer>> incomingList = Lists.newArrayList(a,b,c);
        System.out.println(incomingList);
    
        // Create combined list
        Iterable<Integer> tempList = Iterables.concat(incomingList);
    
        // Re-Partition list 
        Iterable<List<Integer>> result = Iterables.partition(tempList, 2); // New size: 2
    
        // Convert from Iterables to List
        List<List<Integer>> finalList = Lists.newArrayList(result);
        System.out.println(finalList);
    }
    

    输出是:

    [[1, 2, 3], [4, 5, 6], [7, 8, 9]]      // Incoming list
    [[1, 2], [3, 4], [5, 6], [7, 8], [9]]  // Final list
    

    以上代码易于调试,您可以减少代码行数并利用 import static 使其更具可读性并具有以下功能:

    import static com.google.common.collect.Iterables.*;
    import static com.google.common.collect.Lists.*;
    
    public void test(){
        List<Integer> a = newArrayList(1,2,3);
        List<Integer> b = newArrayList(4,5,6);
        List<Integer> c = newArrayList(7,8,9);
    
        List<List<Integer>> incomingList = newArrayList(a,b,c);
        System.out.println(incomingList);
    
        // Repartition
        List<List<Integer>> finalList = newArrayList(partition(concat(incomingList), 2));
        System.out.println(finalList);
    }
    

    作为结果列表的注释,分区方法创建多个包含 N 个值的列表,但最后一个列表可以有更少的值。对于您所说的,您似乎希望在一开始就使用较少的值。我把它留给你搜索分区方法和番石榴用法。

    【讨论】:

      猜你喜欢
      • 2019-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-07
      • 2012-06-03
      • 1970-01-01
      • 2010-09-27
      • 2012-06-12
      相关资源
      最近更新 更多