I am trying to make a function which takes in 4 nested lists as input and returns a single conjoined nested list of the 4 input lists combined in a square shape. The first list would be the upper left corner, second list upper right, third bottom left, fourth bottom right. Note, the length of all 4 lists will always be the same. Also, the amount of elements in the inner lists will always equal the amount of inner lists.
For example, if the input is: list1=[[1,2], [3,4]], list2=[[2,1], [4,3]], list3=[[3,4], [1,2]], list4=[[4,3], [2,1]]
the output would be [[1,2,2,1], [3,4,4,3], [3,4,4,3], [1,2,2,1]] because it would be visualized as:
List1 List2
[1,2] [2,1]
[3,4] [4,3]
List3 List4
[3,4] [4,3]
[1,2] [2,1]
Right now, The pseudocode I have been able to come up with is as follows:
function combine(l1, l2, l3, l4):
list final = [];
for (int i = 0; i < (l1.length * 2; i ):
list new = [];
for (int j = 0; j < l1.length; j ):
new.append(i'th list[j]);
final.append(new);
return final;
I can't seem to figure out how to access the correct elements of the correct array to perform this because this function should perform correctly for any set of 2^n * 2^n arrays.
Any help would be greatly appreciated!
CodePudding user response:
I cannot see that you have specified any language requirement, so even though your list examples suggest that you may not be using C#
, I will suggest a C#
approach that uses Linq operations Enumerable.Concat()
and Enumerable.Zip()
.
(Hopefully the idea could be helpful, even if you can't use the specific implementation.)
The idea is the following:
- Concatenate the elements (element by element) of list1 and list2
- Concatenate the elements (element by element) of list3 and list4
- Concatenate the result obtained in the first step with the result obtained in the second step
Element-wise concatenation of lists with the same length is straight forward when using the .Zip()
operation, as it lets you operate on two sequences element-wise. In this approach, I am using the overload that takes two sequences and defines a result selector. The result selector lets you define what should be done with each element pair of the two sequences.
The "square combination" can be generated as follows:
List<List<int>> squareCombined = list1
.Zip(list2, ( el1, el2 ) => el1.Concat(el2).ToList())
.Concat(list3
.Zip(list4, ( el3, el4 ) => el3.Concat(el4).ToList()))
.ToList();
In the first .Zip()
operation, the sequences are list1
and list2
. The result selector is
( el1, el2 ) => el1.Concat(el2).ToList()
, where el1
references an element from list1
and el2
references an element from list2
. el1
and el2
will always have the same index in their respective sequence.
In the example you have provided, list1
and list2
look as follows:
{ { 1, 2 }, { 3, 4 } } // list1
{ { 2, 1 }, { 4, 3 } } // list2
For the first element pair in the first .Zip()
operation, the result selector therefore produces:
// ( { 1, 2 }, { 2, 1 } ) => { 1, 2 }.Concat({ 2, 1 }).ToList()
{ 1, 2, 2, 1 }
Similarily, for the second element pair in the first .Zip()
operation, the result selector produces:
// ( { 3, 4 }, { 4, 3 } ) => { 3, 4 }.Concat({ 4, 3 }).ToList()
{ 3, 4, 4, 3 }
The return value from the first .Zip()
operation is an IEnumerable<List<int>>
containing those two lists:
{
{ 1, 2, 2, 1 },
{ 3, 4, 4, 3 }
}
By performing an identical .Zip()
operation on list3
and list4
, and then concatenating the two resulting IEnumerable<List<int>>
objects, you obtain a single collection.
This implementation uses the System
, System.Collections.Generic
and System.Linq
namespaces.
Example fiddle here.