Rotate - Transposing a List<List<String>> Using Linq C#

Rotate - Transposing a ListListstring using LINQ C#

This is a simple and flexible solution, it will handle multiple inner lists with any number of dimensions.

List<List<string>> PersonInfo = new List<List<string>>()
{
new List<string>() {"John", "Peter", "Watson"},
new List<string>() {"1000", "1001", "1002"}
};

var result = PersonInfo
.SelectMany(inner => inner.Select((item, index) => new { item, index }))
.GroupBy(i => i.index, i => i.item)
.Select(g => g.ToList())
.ToList();

Transpose a Jagged ListListString to a Rectangular One Using Linq C#

Well, if we want to transpose jagged collection, e.g.

  var source = new string[][] {
new string[] {"a", "b", "c"},
new string[] {"d"},
new string[] {"e", "f"},
new string[] {"g", "h", "i", "j"},
};

we can compute number of columns: I've put .Count() so both List<List<string>> and string[][] will do.

  int columns = source.Max(line => null == line ? 0 : line.Count());

and then if we want to exclude nulls filter out lines which don't have required number of items:

  // Change .ToArray() to .ToList() if you want to have jagged List
var result = Enumerable
.Range(0, columns)
.Select(c => source
.Where(line => line != null && line.Count() > c)
.Select(line => line[c])
.ToArray())
.ToArray();

Let's have a look:

  string report = string.Join(Environment.NewLine, result
.Select(line => string.Join(" ", line.Select(c => c ?? "-"))));

Console.Write(report);

Outcome:

a d e g
b f h
c i
j

Note, that transposing with nulls for holes will be

var result = Enumerable
.Range(0, columns)
.Select(c => source
.Select(line => line == null || line.Count() <= c ? null : line[c])
.ToArray())
.ToArray();

Outcome:

a d e g
b - f h
c - - i
- - - j

How to transpose rows of string into columns using lists in a foreach nested loop C#

The easy way of doing this is to do it without a foreach loop, and use a for loop abusing the fact that you can simply swap the column and row indexes.

using System.Text;

static string TransposeRowsToColumns(string rowString)
{
string[] rows = rowString.Split("\n");

StringBuilder columnBuilder = new StringBuilder();

for (int columnIndex = 0; columnIndex < rows[0].Length; columnIndex++)
{
for (int rowIndex = 0; rowIndex < rows.Length; rowIndex++)
{
columnBuilder.Append(rows[rowIndex][columnIndex]);
}

columnBuilder.Append("\n");
}

return columnBuilder.ToString();
}

Note that the above code relies on the fact that the number of columns is uniform.

If you're wanting to do this with a foreach loop with lists, you can do it like:

static string TransposeRowsToColumnsList(string rowString)
{
string[] rows = rowString.Split("\n");
List<List<string>> grid = new List<List<string>>();

int columnIndex = 0;

foreach (string row in rows)
{
grid.Add(new List<string>());

foreach (string column in rows.Select(r => string.Concat(r.Skip(columnIndex).Take(1))))
{
grid[columnIndex].Add(column);
}

columnIndex++;
}

return string.Join("\n", grid.Select(r => string.Concat(r.Select(c => c))));
}

Usage:

string s = "RLLR" + "\n" + "LRRL" + "\n" + "RVVL" + "\n" + "RRRR"; 

Console.WriteLine(TransposeRowsToColumns(s));
Console.WriteLine(TransposeRowsToColumnsList(s));

Edit

For changing the input to essentially split the columns by space instead of the assumption that they're a single character, we can alter the second method to be like:

static string TransposeRowsToColumnsList(string inputString, string columnSplitBy = "", string rowSplitBy = "\n")
{
IEnumerable<IEnumerable<string>> inputGrid = inputString.Split(rowSplitBy).Select(r =>
{
return columnSplitBy == "" ? r.Select(c => new string(c, 1)).ToArray() : r.Split(columnSplitBy);
});

List<List<string>> outputGrid = new List<List<string>>();

int columnIndex = 0;

foreach (IEnumerable<string> row in inputGrid)
{
outputGrid.Add(new List<string>());

foreach (string column in inputGrid.Select(r => string.Concat(r.Skip(columnIndex).Take(1))))
{
outputGrid[columnIndex].Add(column);
}

columnIndex++;
}

return string.Join(rowSplitBy, outputGrid.Select(r => string.Concat(string.Join(columnSplitBy, r.Select(c => c)))));
}

Although this gets messy really quick. For a more scalable solution, we can create extension methods to separate each stage of the algorithm and spit out the desired result.

We first define an interface that can convert a string to a desired type with an implementation of converting decimals:

public interface IStringConverter<T>
{
T ConvertFromString(string input);
}

public class DecimalConverter : IStringConverter<decimal>
{
public decimal ConvertFromString(string input)
{
return decimal.Parse(input);
}
}

Next we can define all the extension methods we'll need to transpose the grid to the way we want:

public static class CustomExtensions
{
public static IEnumerable<string> ForceSplit(this string input, string pattern)
{
return pattern != string.Empty ? input.Split(pattern) : input.Select(x => x.ToString());
}

public static IEnumerable<IEnumerable<string>> ConvertToGrid(this string input, string columnSplit = "", string rowSplit = "\n")
{
return input.Split(rowSplit).Select(r => r.ForceSplit(columnSplit));
}

public static IEnumerable<IEnumerable<T>> ConvertToGrid<T>(this string input, IStringConverter<T> converter, string columnSplit = "", string rowSplit = "\n")
{
return input.Split(rowSplit).Select(r => r.ForceSplit(columnSplit).Select(converter.ConvertFromString));
}

public static IEnumerable<IEnumerable<T>> PivotGrid<T>(this IEnumerable<IEnumerable<T>> input)
{
return input
.SelectMany(r => r.Select((c, index) => new {column = c, index}))
.GroupBy(i => i.index, i => i.column)
.Select(g => g.ToList());
}

public static string ConvertToString<T>(this IEnumerable<IEnumerable<T>> input, string columnSplit = "", string rowSplit = "\n")
{
return string.Join(rowSplit, input.Select(r => string.Join(columnSplit, r)));
}
}

Things of note:

  • We are now converting each element into a cell of a desired type through ConvertToGrid
  • We are able to Pivot the grid from rows to columns (thanks to this answer)
  • We can then convert the grid back to string format if desired

Usage

string letters = "RLLR" + "\n" + "LRRL" + "\n" + "RVVL" + "\n" + "RRRR"; 
string numbers = "25.0 45.7 23" + "\n" + "12.4 67.4 0.0" + "\n" + "0.00 0.00 0.00" + "\n" + "67.8 98.4 0.00";

string transposedLetters = TransposeRowsToColumnsList(letters);
string transposedNumbers = TransposeRowsToColumnsList(numbers, " ");

string pivotedLetters = letters
.ConvertToGrid()
.PivotGrid()
.ConvertToString();

string pivotedNumbers = numbers
.ConvertToGrid(new DecimalConverter(), " ")
.PivotGrid()
.ConvertToString(" ");

I personally find the extension method approach more maintainable and more extensible, but the original method is easier to call.

Transpose a ListT using c#

ok, how about,

var typed = invalidDataList
.GroupBy(d => d.Type)
.Select(g => new
{
Type = g.Key,
Data = g.Select(d => d.Data).ToList()
})
.ToList();

var table = new DataTable();
foreach(var type In typed)
{
table.Columns.Add(type.Type);
}

var maxCount = typed.Max(t => t.Data.Count);
for(var i = 0; i < maxCount; i++)
{
var row = table.NewRow();
foreach(var type in typed)
{
if (type.Data.Count > i)
{
row[type.Type] = type.Data[i]
}
}

table.Rows.Add(row);
}

Turning an IEnumerableIEnumerableT 90 degrees

I'm a little iffy about this implementation. It has side-effects local to the iterator but looks logically clean to me. This assumes each sequence is the same length but should work for any. You can think of it as a variable length Zip() method. It should perform better than the other linked LINQ solutions found in the other answers as it only uses the minimum operations needed to work. Probably even better without the use of LINQ. Might even be considered optimal.

public static IEnumerable<IEnumerable<T>> Transpose<T>(this IEnumerable<IEnumerable<T>> source)
{
if (source == null) throw new ArgumentNullException("source");
var enumerators = source.Select(x => x.GetEnumerator()).ToArray();
try
{
while (enumerators.All(x => x.MoveNext()))
{
yield return enumerators.Select(x => x.Current).ToArray();
}
}
finally
{
foreach (var enumerator in enumerators)
enumerator.Dispose();
}
}

Reversing Dictionary using LINQ in C#

Update: As others have noted, in order for a dictionary to be truly "reversible" in this way, the values in your List<string> objects need to all be unique; otherwise, you cannot create a Dictionary<string, string> with an entry for every value in your source dictionary, as there would be duplicate keys.

Example:

var dictOne = new Dictionary<string, List<string>>
{
{ "A", new List<string> { "a1", "a2" } },
{ "B", new List<string> { "b1", "b2" } },
{ "C", new List<string> { "c1", "a2" } } // duplicate!
};

You have (at least) two options for dealing with this.

Option 1: Throw on duplicates

You may want to ensure that every element in every List<string> is, in fact, unique. In this case, a simple SelectMany with a ToDictionary will accomplish what you need; the ToDictionary call will throw an ArgumentException on encountering a duplicate value:

var dictTwo = dictOne
.SelectMany(kvp => kvp.Value.Select(s => new { Key = s, Value = kvp.Key }))
.ToDictionary(x => x.Key, x => x.Value);

The most generic way (that comes to mind) to abstract this functionality into its own method would be to implement an extension method that does this for any IDictionary<T, TEnumerable> implementation where TEnumerable implements IEnumerable<TValue>:

// Code uglified to fit within horizonal scroll area
public static Dictionary<T2, T1> ReverseDictionary<T1, T2, TEnumerable>(
this IDictionary<T1, TEnumerable> source) where TEnumerable : IEnumerable<T2>
{
return source
.SelectMany(e => e.Value.Select(s => new { Key = s, Value = e.Key }))
.ToDictionary(x => x.Key, x => x.Value);
}

The ugly proliferation of generic type parameters in the above method is to allow for types other than strictly Dictionary<T, List<T>>: it could accept a Dictionary<int, string[]>, for example, or a SortedList<string, Queue<DateTime>> -- just a couple of arbitrary examples to demonstrate its flexibility.

(A test program illustrating this method is at the bottom of this answer.)

Option 2: Skip duplicates

If duplicate elements in your List<string> values is a realistic scenario that you want to be able to handle without throwing an exception, I suggest you take a look at Gabe's excellent answer for an approach that uses GroupBy (actually, Gabe also provides a flexible approach that can cover either of these two cases based on a selector function; however, if you definitely want to throw on a duplicate, I'd still suggest the above approach, as it should be somewhat cheaper than using GroupBy).

Example program

Here's a little test program illustrating Option 1 above on a Dictionary<string, List<string>> with no duplicate elements in its List<string> values:

var dictOne = new Dictionary<string, List<string>>
{
{ "A", new List<string> { "a1", "a2" } },
{ "B", new List<string> { "b1", "b2" } },
{ "C", new List<string> { "c1" } }
};

// Using ReverseDictionary implementation described above:
var dictTwo = dictOne.ReverseDictionary<string, string, List<string>>();

foreach (var entry in dictTwo)
{
Console.WriteLine("{0}: {1}", entry.Key, entry.Value);
}

Output:


a1: A
a2: A
b1: B
b2: B
c1: C

How to transpose a list of lists, filling blanks with default(T)?

Pretty straightforward:

public static List<List<T>> Transpose<T>(List<List<T>> lists)
{
var longest = lists.Any() ? lists.Max(l => l.Count) : 0;
List<List<T>> outer = new List<List<T>>(longest);
for (int i = 0; i < longest; i++)
outer.Add(new List<T>(lists.Count));
for (int j = 0; j < lists.Count; j++)
for (int i = 0; i < longest; i++)
outer[i].Add(lists[j].Count > i ? lists[j][i] : default(T));
return outer;
}

Is there a LINQ operator to do this?

To make the result independent of the number of arrays the function should loop trough all arrays and keep returning until all enumerations are exhausted:

public static IEnumerable<IEnumerable<T>> Transpose<T>(this IEnumerable<IEnumerable<T>> source)
{
var enumerators = source.Select(e => e.GetEnumerator()).ToArray();
try
{
var next = false;
do
{
var results = enumerators.Select(enr =>
{
if (enr.MoveNext())
{
return enr.Current;
}
return default;
}).ToList();
next = results.Any(e => !Equals(default, e));
if (next)
{
yield return results;
}
}
while (next);
}
finally
{
Array.ForEach(enumerators, e => e.Dispose());
}
}

Now you can use any number of arrays:

var one = new[] { "A", "B", "C" };
var two = new[] { "A", "B", "C", "D" };
var three = new[] { "U", "V","W", "X", "Y", "Z" };
var combined = new[] { one, three, two };
var result = combined.Transpose().SelectMany(e => e).ToList();

This will result in

"A","U","A","B","V","B","C","W","C",null,"X","D",null,"Y",null,null,"Z",null

Filtering the null values is trivial.

(Courtesy this answer for the basic idea, but only working for arrays of equal length).

C# Linq rows to column

The kind of operation you need is called a pivot. You are effectively rotating the table around a unique productRef and changing the rows to columns.

You could try this which makes use of a dynamic object which you require for dynamic column generation.

var configrefs = from c in (
from e in db.Metrics
join j in db.ProgramLink on e.ProjectRef equals j.LinkedProject
where (j.ProjectRef == id) && e.PartitNo == partit
select new
{
FieldName = e.FieldName,
FieldContents = e.MetricValue,
ProjectRef = e.ProjectRef,

}).ToArray();

return configrefs.ToPivotArray(
i => i.FieldName,
i => i.ProjectRef,
items => items.Any() ? items.FirstOrDefault().FieldContents : null);

Private method to get dynamic object:

private static dynamic GetAnonymousObject(IEnumerable<string> columns, IEnumerable<object> values)
{
IDictionary<string, object> eo = new ExpandoObject() as IDictionary<string, object>;
int i;
for (i = 0; i < columns.Count(); i++)
{
eo.Add(columns.ElementAt<string>(i), values.ElementAt<object>(i));
}
return eo;
}

And the extension method

public static dynamic[] ToPivotArray<T, TColumn, TRow, TData>(
this IEnumerable<T> source,
Func<T, TColumn> columnSelector,
Expression<Func<T, TRow>> rowSelector,
Func<IEnumerable<T>, TData> dataSelector)
{

var arr = new List<object>();
var cols = new List<string>();
String rowName = ((MemberExpression)rowSelector.Body).Member.Name;
var columns = source.Select(columnSelector).Distinct();

cols =(new []{ rowName}).Concat(columns.Select(x=>x.ToString())).ToList();

var rows = source.GroupBy(rowSelector.Compile())
.Select(rowGroup => new
{
Key = rowGroup.Key,
Values = columns.GroupJoin(
rowGroup,
c => c,
r => columnSelector(r),
(c, columnGroup) => dataSelector(columnGroup))
}).ToArray();

foreach (var row in rows)
{
var items = row.Values.Cast<object>().ToList();
items.Insert(0, row.Key);
var obj = GetAnonymousObject(cols, items);
arr.Add(obj);
}
return arr.ToArray();
}

How to find modal value accross ListListdouble for each inner value?

Not the most elegant way, but probably easier to Understand. It has been succesfully tested :)

class Program
{
static void Main(string[] args)
{
Random rnd = new Random();
int numberOfLoops = 10;

List<List<int>> myFullList = new List<List<int>>();
for (int i = 0; i < numberOfLoops; i++)
{
List<int> myInnerList = new List<int>();
for (int j = 0; j < 10; j++)
{
// Populate inner list with random numbers
myInnerList.Add(rnd.Next(0, 10));
}

// Add the inner list to the full list
myFullList.Add(myInnerList);
}

myFullList = Transpose<int>(myFullList);

List<int> result = new List<int>();
foreach (List<int> subList in myFullList)
result.Add(Mode(subList));

//TO-DO: linq version!
//List<int> result = myFullList.ForEach(num => Mode(num));

}

public static int Mode(List<int> x)
{
int mode = x.GroupBy(v => v)
.OrderByDescending(g => g.Count())
.First()
.Key;

return mode;
}

public static List<List<T>> Transpose<T>(List<List<T>> lists)
{
var longest = lists.Any() ? lists.Max(l => l.Count) : 0;
List<List<T>> outer = new List<List<T>>(longest);
for (int i = 0; i < longest; i++)
outer.Add(new List<T>(lists.Count));
for (int j = 0; j < lists.Count; j++)
for (int i = 0; i < longest; i++)
outer[i].Add(lists[j].Count > i ? lists[j][i] : default(T));
return outer;
}
}


Related Topics



Leave a reply



Submit