将ArrayList转换为包含不同长度数组的2D数组

32

所以我有:

ArrayList<ArrayList<String>> 

这个包含x个ArrayLists,每个ArrayList还包含y个字符串。举个例子:

Index 0:
  String 1
  String 2
  String 3
Index 1:
  String 4
Index 2:
Index 3:
  String 5
  String 6

这里的索引是指包含字符串的数组索引。

我该如何将其转换为一个类似于以下结构的二维数组:

{{String1, String2, String3},{String4}, {}, {String5, String6}}

非常感谢你。


这里有一个涉及到 int 数组(原始数据类型)的答案:https://dev59.com/Smgu5IYBdhLWcg3wRlFh#62973865 - MasterJoe
8个回答

59

欢迎来到Java 8的世界!

为了写出这一行代码,我熬了一个通宵没睡觉,学习了所有必要的内容。虽然可能已经有人写过了,但我没有找到。所以我分享了我数小时的研究成果,希望你们喜欢。耶!

假设:

ArrayList<ArrayList<String>> mainList = new ArrayList<ArrayList<String>>();
// populate this list here
< p >(或者更确切地说,在Java 8中:< / p >
ArrayList<ArrayList<String>> mainList = new ArrayList();
//Populate

)

然后你所需要的就是:
String[][] stringArray = mainList.stream().map(u -> u.toArray(new String[0])).toArray(String[][]::new);

嘭!一行代码。

我不确定它与其他选项相比有多快。但是它的工作原理如下:

  1. 获取mainList 2D ArrayList的流。这个流有点像一个Vector和LinkedList混合在一起生下来的孩子,而这个孩子稍后又服用了一些NZT-48。我跑题了;mainList.stream()返回一个ArrayList<String>元素的流。或者更加极客的说法:mainList.stream()返回一个Stream<ArrayList<String>>,差不多。

  2. 在该流上调用.map函数,它将返回一个新的流,其中的内容与传递给map的参数指定的新类型匹配。这个map函数会为我们转换流中的每个元素。它内置了一个foreach语句。为了完成这个操作,map函数将一个Lambda表达式作为其参数。Lambda表达式就像一个简单的内联单行函数。它有两种数据类型gettin' Jiggy wit it。第一种是调用它的流中的数据类型(mainList.stream())。下一个类型是它将要映射的数据类型,在Lambda表达式的右半部分:u -> u.toArray(new String[0])。这里的u是你选择的标识符,就像使用foreach语句时一样。前半部分声明如下:u ->。就像foreach一样,变量u将在遍历流时成为每个元素。因此,u是原始流元素的数据类型,因为它们它们。Lambda表达式的右半部分显示了对每个元素的操作:u.toArray(new String[0])。结果存储在新流中的正确位置。在这种情况下,我们将其转换为String[]。因为毕竟,这是一个2D数组的String。或者从代码的这一点开始,一个String[](字符串数组)的1D数组。请记住,u最终是一个ArrayList。请注意,从ArrayList对象调用toArray将创建一个传递到其中的类型的新数组。在这里,我们传入new String [0]。因此,它创建一个类型为String[]且长度等于uArrayList长度的新数组。然后用ArrayList的内容填充这个新的字符串数组并返回它。这样就离开了Lambda表达式,回到map。然后,map收集这些字符串数组并创建一个新的流,它具有关联类型String[],然后返回它。因此,在这种情况下,map返回一个Stream<String[]>。(好吧,实际上它返回一个Stream<Object[]>,这很令人困惑,需要转换,请参见下文)。

  3. 因此,我们只需要在字符串数组的新流上调用toArray。但是,在ArrayList<String>之前调用toArray与在Stream<Object[]>上调用它有点不同

    将二维整数ArrayList转换为二维原始int数组

    现在,我知道你们中的一些人会说:“这对于int不起作用!” 就像我的情况一样。 但是,它确实适用于“Ents”,请参见上文。 但是,如果您想从二维ArrayList<ArrayList<Integer>>(即ArrayList的二维)获得二维基本类型int数组。 您需要改变那个中间[地球]映射。 请记住,ArrayList无法具有基本类型。 因此,您无法在ArrayList<Integer>上调用toArray并期望获得int[]。 您需要再次进行映射。

    int[][] intArray = mainList.stream().map(  u  ->  u.stream().mapToInt(i->i).toArray()  ).toArray(int[][]::new);
    

    我尝试将其分开以便阅读。但是您可以看到,我们必须再次进行完整的映射过程。这一次,我们不能像上面的例子那样只需在ArrayList u 上简单地调用 toArray ; 在这里,我们正在对 Stream 而不是 ArrayList 调用 toArray 。因此,出于某种原因,我们不必传递“类型”,我认为它正在接受大脑类固醇。因此,我们可以采用默认选项;其中它会吸食NZT-48并为我们计算明显的[运行]时间。我不确定为什么它不能在上面的例子中做到这一点。哦,对了.... ArrayLists不像Streams一样吸食NZT-48。等等...我在这里说些什么?

    无论如何,由于流非常智能,就像谢尔顿一样,我们需要一个全新的协议来处理它们。显然,先进的智能并不总是易于处理。因此,这个新的mapToInt被需要用来创建一个新的Stream,以便我们可以使用它更聪明的toArray。而mapToInt中的i->i Lambda表达式是将Integer简单地拆箱为int,使用了隐式自动拆箱,允许int = Integer。现在看来,这似乎是一件愚蠢的琐事,好像智能也有其局限性。在我学习所有这些的过程中:我实际上尝试使用mapToInt(null),因为我期望有一个默认行为。结果却是一个参数!(咳咳谢尔顿咳咳)然后我用最好的Husker山谷女孩口音说:"毕竟,它被称为mapToInt,我猜,84%的时间(42x2),它会像i->i一样被每个人传递,所以就像,天哪!"不用说,我感觉有点...像这个家伙this guy。我不知道,为什么它不是那样工作的。

    我很疲惫,头脑有些混乱,也有些困意。可能会出现一些错误,请帮忙指出来,以便我进行修正,并让我知道是否有更好的方法!

    PT


由于 'map' 接受 Lambda (据说知道 Lambda 的每一侧的数据类型),因此它应该能够将该数据类型信息传递下去。因此,尽管我有些疯狂的胡言乱语,但我仍然希望得到上述两个问题的答案: 1)为什么 'map' 实际上返回一个 Stream<Object[]>,而不是 Lambda 表达式内返回类型的流作为默认行为? 2)为什么 'mapToInt' 没有默认使用 i->i - Pimp Trizkit
我使用了你的答案 https://pastebin.com/iNkwetbW。当我在IntelliJ IDEA中编写代码时,我收到了一个警告,它覆盖了多个方法。我该如何消除这些警告? - Mestica
覆盖?那听起来很奇怪。我不会说这行代码覆盖了什么。但我不知道IntelliJ IDEA是什么,以及它所处的环境。我无法提供任何帮助。我希望这里的其他人能够阅读并帮助您解决问题。也许可以将语句分解为较小的部分,并逐个测试它们,看看问题出在哪里。例如,尝试从ArrayList中提取.stream()并将其打印到屏幕上,以确保该部分有效...然后继续进行.map()...等等。 - Pimp Trizkit
我会选择新的ArrayList<>()(而不是new ArrayList()) - Enrico Giurin
如果有人需要将一个二维整数数组转换为列表的可用代码,请访问以下链接:https://stackoverflow.com/a/62973891/6648326 - MasterJoe

46
String[][] array = new String[arrayList.size()][];
for (int i = 0; i < arrayList.size(); i++) {
    ArrayList<String> row = arrayList.get(i);
    array[i] = row.toArray(new String[row.size()]);
}

其中arrayList是你的ArrayList<ArrayList<String>>(或任何List<List<String>>,相应地更改for循环内的第一行)


1
如果我有一个ArrayList<String[]>,想将其转换为二维数组,该怎么办? - shridatt
4
抱歉,我错过了这个问题,也许你已经解决了……不管怎样,它很简单:String[][] array2D = new String[arrayList.size()][]; for (int i = 0; i < array2D.length; i++) { String[] row = arrayList.get(i); array2D[i] = row; }arrayList 转换为二维字符串数组 array2D,其中每个元素都是一个字符串数组。具体实现是遍历 array2D 的每一行并将其赋值给 row,然后将 row 分配给相应的 array2D 行。 - michele b
对我没用。最终的二维数组每行只有一列。 - rafa
你是如何进行检查的,你的输入又是什么样子的? - michele b

6
您可以使用toArray()方法将ArrayList转换为数组。由于您的ArrayList中包含另一个ArrayList,因此您需要对每个元素进行迭代并应用此方法。
类似这样:-
ArrayList<ArrayList<String>> mainList = new ArrayList<ArrayList<String>>();
// populate this list here
//more code

// convert to an array of ArrayLists
ArrayList<String[]> tempList = new ArrayList<String[]>();
for (ArrayList<String> stringList : mainList){
    tempList.add((String[])stringList.toArray());
}

//Convert to array of arrays - 2D array
String [][]list = (String[][])tempList.toArray();

你可以在这里了解更多关于toArray()的内容。

2

例如:

public String[][] toArray(List<List<String>> list) {
    String[][] r = new String[list.size()][];
    int i = 0;
    for (List<String> next : list) {
       r[i++] = next.toArray(new String[next.size()]);
    }
    return r;
}

1
ArrayList<ArrayList<String>> list= new ArrayList<ArrayList<String>>();
          ArrayList<String> a = new ArrayList<String>();
          ArrayList<String> b = new ArrayList<String>();
          a.add("Hello");
          b.add("Hell");
          list.add(a);
          list.add(b);
          Object[][] array = new Object[list.size()][];
          Iterator<ArrayList<String>> iterator = list.iterator();
          int i = 0;
          while(iterator.hasNext()){
              array[i] = iterator.next().toArray();
          }

你可以使用下面的代码片段将 Object[] 转换为 String[]。
String[] stringArray = Arrays.copyOf(objectArray, objectArray.length, String[].class);

1
    int[][] array = new int[list.size()][]; 
    for (int i = 0; i < array.length; i++) { 
        array[i] = new int[list.get(i).size()]; 
    } 
    for(int i=0; i<list.size(); i++){ 
        for (int j = 0; j < list.get(i).size(); j++) { 
            array[i][j] = list.get(i).get(j); 
        } 
    } 

1
你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心找到有关如何编写良好答案的更多信息。 - Community

0

这个完整的小程序代码以相当自我解释的方式回答了这个问题。只需粘贴并运行它:

import java.util.ArrayList;
import java.util.List;

public class ListTo2Darray {

    public String[][] toArray(List<List<?>> list) {
    String[][] r = new String[list.size()][];
    int i = 0;
    for (List<?> next : list) {
       r[i++] = next.toArray(new String[next.size()]);
    }
    return r;
}

    public static void main(String[]arg){
        String[][] sham;

        List<List<?>> mList = new ArrayList();

        List<String> a= new ArrayList();
        List<String> b= new ArrayList();
        a.add("a");  a.add("a");
        b.add("b");  b.add("b");
        mList.add(a); mList.add(b); 

        ListTo2Darray mt= new ListTo2Darray();
        sham=   mt.toArray(mList);

        System.out.println(sham[0][0]);
        System.out.println(sham[0][1]);
        System.out.println(sham[1][0]);
        System.out.println(sham[1][1]);
    }

}

0
queries=[[1,5,3],[4,8,7],[6,9,1]]
h=queries.size();

        for(i=0;i<h;i++){
            for(j=0;j<3;j++){
                y[i][j]= ( ( queries.get(i) ).get(j) );
            }  
        }

它将做的是,在这个语句中,首先查询queries.get(i)将选择列表i的第一个块,即在i=0时,它将选择[1,5,3],然后在j=0时,它将从[1,5,3]中选择1,以此类推。

循环解释: y[][]=[ 1 5 3 4 8 7 6 9 1 ]

注意:请用您提供的数组替换queries。

请告诉我是否有效,或者我应该提供另一种解决问题的方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接