i have the following simplified input:
List<string[]> sList = new List<string[]>();
sList.Add(new string[]{ "Product", "ProductID"});
sList.Add(new string[] { "Fork", "1" });
sList.Add(new string[] { "Spoon", "2" });
sList.Add(new string[] { "Knife", "3" });
and i want the following output
ResultList[0] == { "Product" ,"Fork","Spoon","Knife"};
ResultList[1] == { "ProductID" ,"1","2","3"};
first i solved this with 2 loops, then i changed my approach to this linq (both working):
List<string[]> Result = sList.SelectMany(x => x)
.Select((x, index) => new KeyValuePair<int, string>(index % sList.First().Length, x))
.GroupBy(s => s.Key).Select(g => g.Select(x => x.Value)
.ToArray()).ToList();
it works but it seems to be a bit circuitous to me. isn't there a simpler approach (built in?) i've overlooked?
There's a better solution for this: use Dictionary<TKey, TValue>.
Dictionary<string, string> products = new Dictionary<string, string>()
{
{ "Fork", "1" },
{ "Spoon", "2" }
};
Now you can access products.Keys (which will get product names) and products.Values (which will get product identifiers):
ResultList[0] = new [] { "Product" }.Union(products.Values);
ResultList[1] = new [] { "ProductID" }.Union(products.Keys);
Possible automatization:
List<List<string>> resultList = new [] { "Product", "ProductID" }
.Select((g, index) => (index == 0 ? new [] { g }.Union(products.Keys) : new [] { g }.Union(products.Values)).ToList())
.ToList();
BTW, as long as you've stored your data in a dictionary, I don't find a reason to add "column names" to the result if you know that product names are products.Keys and identifiers products.Values. That is, you can work with the dictionary directly...
So if you know for sure that each array contains exactly 2 elements, problem becomes a combination of two trivial selecs. However if you only know that all arrays are of the same size, but do not want to rely on exact numbers, this approach should do it:
List<string[]> Result =
sList.First()
.Select((x, i) => i)
.Select(i => sList.Select(x => x[i]).ToArray())
.ToList();
We are basically using first item in sList to figure out how many members there are in the array, and then doing a select for each of them.
What about something like this:
List<string[]> sList = new List<string[]>();
sList.Add(new string[] { "Product", "ProductID" });
sList.Add(new string[] { "Fork", "1" });
sList.Add(new string[] { "Spoon", "2" });
sList.Add(new string[] { "Knife", "3" });
var res = new List<string[]> { sList.Select(a => a[0]).ToArray(), sList.Select(b => b[1]).ToArray() };
Related
So I have a list of array of strings like below:
List<string[]> ArrayList = new List<string[]>();
ArrayList.Add(new string[] { "7112432","Gagan","Human Resource"});
ArrayList.Add(new string[] { "7112433", "Mukesh", "Information Technology" });
ArrayList.Add(new string[] { "7112434", "Steve", "Human Resource" });
ArrayList.Add(new string[] { "7112435", "Trish", "Human Resource" });
I want them to convert them to separate arrays like:
EmployeeNumber=["7112432","7112433","7112434","7112435"]
Name =["Gagan", "Mukesh", "Steve", "Trish"]
Department =["Human Resource", "Information Technology", "Human Resource", "Human Resource"]
I have achieved it by looping through the list using foreach but I want to know if there is any efficient way of doing this because I have like 20 million items in the original List
This solution inspired me: Rotate - Transposing a List<List<string>> using LINQ C#
Here the code you can use for your needs:
List<string[]> ArrayList = new List<string[]>();
for (int i = 0; i < 20000000; i++)
{
//The simulation of the 20.000.000 arrays of the list takes some time (+- 10s)...
//But you already have the list so you can skip this part of the code
ArrayList.Add(new string[] { i.ToString(), "Gagan", "Human Resource", "AAA" });
}
var millis = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
List<List<string>> results = ArrayList.SelectMany
(theArray => theArray.Select((itemInArray, indexInArray) => new { itemInArray, indexInArray })) //All single elements
.GroupBy(i => i.indexInArray, i => i.itemInArray) //Group them
.Select(g => g.ToList())
.ToList();
var seconds = (DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - millis) / 1000d; //9.8 s
I have this list:
var items = new List<string>() { "Hello", "I am a value", "Bye" };
I want it to convert it to a dictionary with the following structure:
var dic = new Dictionary<int, string>()
{
{ 1, "Hello" },
{ 2, "I am a value" },
{ 3, "Bye" }
};
As you can see, the dictionary keys are just incremental values, but they should also reflect the positions of each element in the list.
I am looking for a one-line LINQ statement. Something like this:
var dic = items.ToDictionary(i => **Specify incremental key or get element index**, i => i);
You can do that by using the overload of Enumerable.Select which passes the index of the element:
var dic = items.Select((val, index) => new { Index = index, Value = val})
.ToDictionary(i => i.Index, i => i.Value);
static void Main(string[] args)
{
var items = new List<string>() { "Hello", "I am a value", "Bye" };
int i = 1;
var dict = items.ToDictionary(A => i++, A => A);
foreach (var v in dict)
{
Console.WriteLine(v.Key + " " + v.Value);
}
Console.ReadLine();
}
Output
1 Hello
2 I am a value
3 Bye
EDIT: Out of curosity i did a performance test with a list of 3 million strings.
1st Place: Simple For loop to add items to a dictionary using the loop count as the key value. (Time: 00:00:00.2494029)
2nd Place: This answer using a integer variable outside of LINQ. Time(00:00:00.2931745)
3rd Place: Yuval Itzchakov's Answer doing it all on a single line. Time (00:00:00.7308006)
var items = new List<string>() { "Hello", "I am a value", "Bye" };
solution #1:
var dic2 = items.Select((item, index) => new { index, item })
.ToDictionary(x => x.item, x => x.index);
solution #2:
int counter = 0;
var dic = items.ToDictionary(x => x, z => counter++);
I have this list
// sample data
List<string[]> ListOfArrays = new List<string[]> { new string[]{ "key1", "key2", "key3" },
new string[]{ "value1", "value2", "value3" },
new string[]{ "item1", "item2", "item3" , "item4"} };
i want to join all paralleled indexes in the array with comma delimited string, this will result in converting List<string[]> to string[]
The expected result
// expected result
string[] joinedList = new string[] { "key1, value1, item1",
"key2, value2, item2",
"key3, value3, item3",
"item4"};
is there a simple way to do this ? something like
string[] string.JoinMultiple(string delimiter, List<string[]>);
in the above case could be used like
string[] joinedList = string.JoinMultiple(",", ListOfArrays);
i've been searching a lot to find a solution for this but with no hope.
You can try this:
string[] joinedList = listOfArrays.SelectMany(
strings => strings.Select((s, i) => new {s, i}))
.ToLookup(arg => arg.i, arg => arg.s)
.Select(grouping => string.Join(",", grouping)).ToArray();
or extension method:
string[] joinedList = listOfArrays.JoinMultiple(",");
...
public static string[] JoinMultiple(this List<string[]> lists,string delimiter)
{
return lists.SelectMany(
strings => strings.Select((s, i) => new {s, i}))
.ToLookup(arg => arg.i, arg => arg.s)
.Select(grouping => string.Join(delimiter, grouping)).ToArray();
}
I just put this method together. It produces the results you described.
public static string[] JoinMultiple(string delimiter, List<string[]> lists)
{
int maxListLength = lists.Max(l => l.Count());
string[] result = new string[maxListLength];
for (int i = 0; i < maxListLength; i++)
{
result[i] = String.Join(delimiter,
lists.Select(l => (i < l.Count()) ? l[i] : null)
.Where(s => s != null));
}
return result;
}
I have a jagged array that looks like this:
string[][] list = new string[d.Rows.Count + 1][];
int c = 0;
while (c < d.Rows.Count)
{
list[c] = new string[]
{
d.Rows[c].ItemArray[2].ToString(),
d.Rows[c].ItemArray[1].ToString(),
d.Rows[c].ItemArray[4].ToString(),
d.Rows[c].ItemArray[5].ToString(),
d.Rows[c].ItemArray[7].ToString(),
d.Rows[c].ItemArray[3].ToString(),
d.Rows[c].ItemArray[14].ToString()
};
c += 1;
}
return list;
Now, for a new requirement, i need only the items from this array whose value at this location: list[x][0] are equal to any of the following strings: "Text", "FullText", "FullMatch"
I got started with a regular array i could do this: but it obvioulsy won't work for a jagged array.
string[][] newlist = list.where(item => item.equals("Text");
Does any one know how to extend this for my situation?
You can do a where on list which will iterate over each one-dimensional array, then compare element 0 to the strings given.
string[][] newlist = list
.Where(item => item[0].Equals("Text")
|| item[0].Equals("FullText")
|| item[0].Equals("FullMatch"))
.ToArray();
Tested this on some sample data as shown below:
var list = new string[][]
{
new string[] { "Text", "A", "B", "C", "D" },
new string[] { "None", "Z", "C" },
new string[] { "FullText", "1", "2", "3" },
new string[] { "FullMatch", "0", "A", "C", "Z" },
new string[] { "Ooops", "Nothing", "Here" },
};
string[][] newlist = list.Where(item => item[0].Equals("Text")
|| item[0].Equals("FullText")
|| item[0].Equals("FullMatch")).ToArray();
// now display all data...
foreach (string[] row in newlist)
{
Console.Write("Row: ");
foreach (string item in row)
{
Console.Write(item + " ");
}
Console.WriteLine();
}
This worked correctly with output being:
Row: Text A B C D
Row: FullText 1 2 3
Row: FullMatch 0 A C Z
If you wanted a fully LINQ-based solution, then I think the following should do the trick (although I haven't tested it, because I'm not usre what the variable d refers to):
var res =
(from c in Enumerable.Range(0, d.Rows.Count)
let list = new string[] {
d.Rows[c].ItemArray[2].ToString(),
d.Rows[c].ItemArray[1].ToString(),
d.Rows[c].ItemArray[4].ToString(),
d.Rows[c].ItemArray[5].ToString(),
d.Rows[c].ItemArray[7].ToString(),
d.Rows[c].ItemArray[3].ToString(),
d.Rows[c].ItemArray[14].ToString()
}
where list[0] == "Text" || list[0] == "FullText" || list[0] == "FullMatch"
select list).ToArray();
A jagged array is just an array of arrays, so you can process it using LINQ. The only trick is that individual items will be arrays (representing your columns). After using Where, you can turn the result back to an array using ToArray:
string[][] newlist = list.Where(item => item[0] == "Text" || ... ).ToArray();
How do you query a List<string[]> to get the index of the arrays having matches on their sub-arrays and get a return of type System.Collections.Generic.IEnumerable<string[]> ?
EDIT:
I have this:
string[] report = File.ReadAllLines(#".\REPORT.TXT").AsQueryable().Where(s
=> s.StartsWith(".|")).ToArray();
List<string[]> mylist = new List<string[]>();
foreach (string line in report)
{
string[] rows = line.Split('|');
mylist.Add(rows);
}
and I what to get the the mylist indexes where rows[5] == "foo"
For the original question:
list.Where(array => array.Any(item => item == match))
For the updated one:
result = Enumerable.Range(0, list.Count - 1).Where(i => list[i][5] == "foo");
You do actually need to check if the array has at least 6 items as well:
i => list[i].Length > 5 && list[i][5] == "foo"
You mean something like this?
var haystacks = new List<string[]>();
haystacks.Add(new string[] { "abc", "def", "ghi" });
haystacks.Add(new string[] { "abc", "ghi" });
haystacks.Add(new string[] { "def" });
string needle = "def";
var haystacksWithNeedle = haystacks
.Where(haystack => Array.IndexOf(haystack, needle) != -1);