How to transpose List<List>?
I have a following ArrayList,
[Title,Data1,开发者_运维技巧Data2,Data3]
[A,2,3,4]
[B,3,5,7]
And I would like to convert this one like this,
[Title,A,B]
[Data1,2,3]
[Data2,3,5]
[Data3,4,7]
I'm bit confused with the approach. Any hint would be much appreciated.
Thanks.
This is called transposition. The following snippet does what you need:
import java.util.*;
public class ListTranspose {
public static void main(String[] args) {
Object[][] data = {
{ "Title", "Data1", "Data2", "Data3" },
{ "A", 2, 3, 4 },
{ "B", 3, 5, 7 },
};
List<List<Object>> table = new ArrayList<List<Object>>();
for (Object[] row : data) {
table.add(Arrays.asList(row));
}
System.out.println(table); // [[Title, Data1, Data2, Data3],
// [A, 2, 3, 4],
// [B, 3, 5, 7]]"
table = transpose(table);
System.out.println(table); // [[Title, A, B],
// [Data1, 2, 3],
// [Data2, 3, 5],
// [Data3, 4, 7]]
}
static <T> List<List<T>> transpose(List<List<T>> table) {
List<List<T>> ret = new ArrayList<List<T>>();
final int N = table.get(0).size();
for (int i = 0; i < N; i++) {
List<T> col = new ArrayList<T>();
for (List<T> row : table) {
col.add(row.get(i));
}
ret.add(col);
}
return ret;
}
}
See also
- Wikipedia/Transpose
Here is my solution.Thanks to @jpaugh's code.I hope this will help you.^_^
public static <T> List<List<T>> transpose(List<List<T>> list) {
final int N = list.stream().mapToInt(l -> l.size()).max().orElse(-1);
List<Iterator<T>> iterList = list.stream().map(it->it.iterator()).collect(Collectors.toList());
return IntStream.range(0, N)
.mapToObj(n -> iterList.stream()
.filter(it -> it.hasNext())
.map(m -> m.next())
.collect(Collectors.toList()))
.collect(Collectors.toList());
}
This called a transpose operation. A code sample is here, , but will need significant modification as you have an ArrayList of Arrays (what I infer from your question)
something like this maybe
List<List<String>> list = new ArrayList<List<String>>(firstList.size());
for(int i = 0; i < firstList.size(); i++) {
list.add(Arrays.asList(
firstList.get(i),
secondList.get(i),
thirdList.get(i))
);
}
The mathematics behind: you need to transpose the matrix. It's easier if you use a 2-dimensional array or a 'List of Lists', which is pretty much he same with collections. A List of arrays works too, but it is slightly more confusing.
This wikipedia article shows some algorithms for transposition.
The technique is called transposing. Example of an implementation.
public static MyObject [][] transpose(MyObject [][] m){
int r = m.length;
int c = m[r].length;
MyObject [][] t = new MyObject[c][r];
for(int i = 0; i < r; ++i){
for(int j = 0; j < c; ++j){
t[j][i] = m[i][j];
}
}
return t;
}
Not a fast way, neither the cleanest one, but more of kotlin-ish code.
fun <T> List<List<T>>.transpose(): List<List<T>> {
val result = (first().indices).map { mutableListOf<T>() }.toMutableList()
forEach { list -> result.zip(list).forEach { it.first.add(it.second) } }
return result
}
the first line creates a M size 'result' list (for NxM original matrix), while the second line =>
- iterates through all the lists 'a' in first (each list size m)
- append i-th item of a to the i-th list in result.
Check whether all lists have the same size.
Place the informations in a Matrix (List with List elements, for example) to get the number of lists and size of a list.
Create a new Matrix with the rotated size informations. (3x4 to 4x3)
Implement 2 For loops and place the elements into the new matrix.
If it is for a datamigration task, you might consider your friendly spreadsheet if the size is not too big.
For matrix manipulation stuff there is the jScience library which has matrix support. For just transposing a metrix this would be overkill, but it depends what needs to be done with it.
Do you have a fixed number of ArrayLists and are they of fixed size to begin with? If it is fixed, what you can do is have an int index value and process each ArrayList in turn in the same loop. You can then transfer each value to a temporary ArrayList and then place a reference to this in a final ArrayList for output.
Sounds confusing? Here's a rough solution:
ArrayList tempList = new ArrayList();
ArrayList outputList = new ArrayList();
for(index=0;index<list1.getsize();index++){
// Add null checks and other validation here
tempList.add( list1.get(index) );
tempList.add( list2.get(index) );
tempList.add( list3.get(index) );
outputList.add( tempList );
}
Since get(index)
could harm your performance dramatically i.e. for big linked list I would recommend using @polygenelubricants solution but with an iterator approach.
public static <T> List<List<T>> transpose(List<List<T>> table) {
List<List<T>> ret = new ArrayList<List<T>>();
final int N = table.stream().mapToInt(l -> l.size()).max().orElse(-1);
Iterator[] iters = new Iterator[table.size()];
int i=0;
for (List<T> col : table) {
iters[i++] = col.iterator();
}
for (i = 0; i < N; i++) {
List<T> col = new ArrayList<T>(iters.length);
for (Iterator it : iters) {
col.add(it.hasNext() ? (T) it.next() : null);
}
ret.add(col);
}
return ret;
}
In Kotlin, a simple transposing would look like:
fun transpose( matrix: List<List<String>> ) {
return matrix.first().forEachIndexed {
i, _ -> matrix.map { it.getOrNull(i) }
}
}
Legend:
forEachIndexed
iterates over indexes of the first row.- Then, each such index is mapped to the items of all rows on that index.
getOrNull
handles the missing items in shorter rows. - That's returned by
map()
as aList
.
精彩评论