Cannot create nested ArrayList from Array in Java
I am trying to create a nested list from an array.
But I have a problem while converting Object
to String
:
Object[] array = new Object[] {
new String[] {"add, hack"},
new String[] {"add, hackerrank"},
new String[] {"find, hac"},
new String[] {"find, hak"}
};
List<List<String>> list = Arrays.asList(Arrays.asList((array.toString())));
So, how can I convert it properly?
Here is the method that reserves the List<List<String>>
:
public static List<Integer> contacts(List<List<String>> queries) {
for (List<String> query : queries) {
String operation = query.get(0); // --> gives "add, hack" (I expect "add")
String word = query.get(1);
}
}
CodePudding user response:
One more solution assuming you want to start from Object[] array - first transforms to list of String[] using casting and then maps every String[] to List:
List<String[]> arrList = new ArrayList<>();
for (Object o : array)
arrList.add((String[]) o);
List<List<String>> strList = arrList.stream()
.map(Arrays::asList)
.collect(Collectors.toList());
CodePudding user response:
In order to be an "array of arrays" it would need to be a 2-dimensional array:
String[][] arrays = new String[][] {new String[] {"add, hack"}, ...}
Then you could convert each array inside the array into an item in the list
List<List<String>> list = new ArrayList<>();
for (String[] array : arrays) {
list.add(Arrays.asList(array));
}
CodePudding user response:
You can stream
the array and then collect to a List
:
Object[] array = new Object[] {
new String[] {"add, hack"},
new String[] {"add, hackerrank"},
new String[] {"find, hac"},
new String[] {"find, hak"}};
List<List<String>> list = Arrays.stream(array)
.map(String[].class::cast)
.map(arr -> arr[0].split(", "))
.map(Arrays::asList)
.collect(Collectors.toList());
System.out.println(list);
Output:
[[add, hack], [add, hackerrank], [find, hac], [find, hak]]
With JDK 16 you can do:
List<List<String>> list = Arrays.stream(array)
.map(String[].class::cast)
.map(arr -> arr[0].split(", "))
.map(Arrays::asList)
.toList();
CodePudding user response:
Every array inside the source array in your code like new String[] {"add, hack"}
is treated as Object
- that's all the compiler knows about it because array
has been declared as Object[]
(i.e. array of objects, not array of arrays objects, or array of arrays of strings).
Arrays.asList(array.toString())
- creates a list with a single element of type String
. And when you invoke toString()
on an array of any type, you will obtain a string containing the array's type and hash-based sequence of symbols after the at-sign @
. In order to get a string representation of the array contents, you need to use static method toString()
of the Arrays
class.
This way you can approach the problem of casting an array of Object
type
public static void main(String[] args) {
Object[][] array = new Object[][]{
new String[] {"add, hack"},
new String[] {"add, hackerrank"},
new String[] {"find, hac"},
{"find, hak"} // you can omit new String[] when assigning array while at the same time with initialization
};
List<List<String>> list = arraysToList(array, String.class);
System.out.println(list);
}
Generic method for casting, that expects a Class
object as a parameter:
public static <T> List<List<T>> arraysToList(Object[][] array, Class<T> clazz) {
return Stream.of(array)
.map(arr -> Stream.of(arr).map(clazz::cast).toList())
.collect(Collectors.toList());
}
Output
[[add, hack], [add, hackerrank], [find, hac], [find, hak]]
Your Question is unclear as to your goal. Perhaps you want to generate text in a specific format. If so, add a method to the record class Query
that returns a String
object in your desired format.
If you need to split a single string containing non-alphabetic symbols into separate words, you can make use of the split()
method:
str.split("[^\\p{Alpha}] "); // returns an array of strings comprised of alphabetic symbols only
CodePudding user response:
Use objects, not lists of arrays
The other Answers seem to be correct about your various problems. I will look at the bigger picture… Your design approach has ignored the the best feature of Java: object-oriented programming.
Your query pieces should be packaged as a class, a record.
record Query ( String verb , String noun ) {}
Apparently you are starting with a comma-separated string as inputs. So add a static factory method to parse each input.
record Query ( String verb , String noun ) {
// Factory method to instantiate `Query` object by parsing input string containing a pair of comma-separated values.
public static Query parse( final String input ) {
String[] parts = input.split( ", " ) ;
return new Query ( parts[0] , parts[1] ) ;
}
}
Skip the arrays, and use List
or Set
for their convenience.
List< Query > queries =
List.of(
Query.parse( "add, hack" ) , // Instantiates a `Query` object.
Query.parse( "add, hackerrank" ) ,
Query.parse( "find, hac" ) ,
Query.parse( "find, hak" )
)
;
Generating text
Report contents.
System.out.println( "queries = " queries );
queries = [Query[verb=add, noun=hack], Query[verb=add, noun=hackerrank], Query[verb=find, noun=hac], Query[verb=find, noun=hak]]
Your Question is not clear as to its end goal. If your goal is to generate text in a particular format, add a method to your class. Here we add a method called report
.
String report ( ) { return String.format( "{ %s, %s }" , this.verb , this.noun ); }
To use that report
method, loop your objects, generating text for each.
queries.forEach( query -> System.out.println( query.report() ) );
{ add, hack }
{ add, hackerrank }
{ find, hac }
{ find, hak }
Caveat: In real work, we would do more to verify and validate. For example we would validate our input data to make sure the input string is non-null, non-blank, and composed of two parts. I omitted such code to keep the demo short and on-point.