int numPics = 3; //Populated from a query
string[] picID = new string[numPics];
//pictureTable is constructed so that it correlates to pictureTable[column][row]
string[][] pictureTable = null; //assume the table has data
for (int i = 0; i < numPics; i++)
{
//LINQ query doesn't work. Returns an IEnumerable<string> instead of a string.
picID[i] = pictureTable.Where(p => p[0].Equals("ID")).Select(p => p[i]);
}
I am new to LINQ, but I've been searching and haven't found an answer. I want to be able to check the first string of every column in my pictureTable using LINQ to see if it matches a string. Then, I want to take that column and extract data from each of the rows from 0 to i. I understand I can do it with a for loop by changing the column and keeping the row the same, but I want to use LINQ to achieve the same result.
Also if it is possible to get rid of the first for loop and achieve the same result, I would really be interested in that as well.
EDIT: Lets say we have a table that has the following data, keep in mind everything is a string.
Column Name [ID] [Name] [Age]
Row 1 [1] [Jim] [25]
Row 2 [2] [Bob] [30]
Row 3 [3] [Joe] [35]
I want to be able to query a columns name, then be able to get data from it, either by index or querying the row's data. I'll give an example using a for loop that achieves what I want.
string[][] table = new string[][] {
new string[] { "ID", "Name", "Age" },
new string[] { "1", "Jim", "25" },
new string[] { "2", "Bob", "30" },
new string[] { "3", "Joe", "35" }};
string[] resultRow = new string[table.GetLength(1)];
for (int i = 0; i < table.GetLength(0); i++)
{
if (table[i][0] == "Name") //Given this in a LINQ Query
{
Console.WriteLine("Column Name = {0}\n", table[i][0]);
for (int j = 1; j < table.GetLength(1); j++) //starts at 1
{
resultRow[i] = table[i][j]; //This is what I want to happen.
}
break; //exit outer loop
}
}
//Output:
//Column Name = Name
I think this would give you the equivalent of what you are looking for in your resultRow array
string[][] table = new string[][] {
new string[] { "ID", "Name", "Age" },
new string[] { "1", "Jim", "25" },
new string[] { "2", "Bob", "30" },
new string[] { "3", "Joe", "35" }
};
//get index of column to look at
string columnName = "Name";
var columnIndex = Array.IndexOf(table[0], columnName, 0);
// skip the title row, and then skip columns until you get to the proper index and get its value
var results = table.Skip(1).Select(row => row.Skip(columnIndex).FirstOrDefault());
foreach (var result in results)
{
Console.WriteLine(result);
}
One other thing to look at would be SelectMany, as you can use it to flatten mlutiple lists into a single list.
Do you just want to concatenate the strings together? If so you can just do this:
picID[i] = string.Concat(pictureTable.Where(p => p[0].Equals("ID")).Select(p => p[i]));
Related
I need to set up a 2D array to hold the names of singers and their gender, and then count the number of males and display it on a label, and the number of females on another label. I've created the array (properly I think) but I do not know how to loop through only the 2nd column. Here's my array:
string[,] singers =
{
{"Beyonce", "F"},
{"David Bowie", "M"},
{"Hikaru Utada", "F"},
{"Madonna", "F"},
{"Elton John", "M"},
{"Koji Tamaki", "M"}
};
I'm very new to C# so any assistance is appreciated.
Instead of string[,] you can use string[][] and do something like
string[,] singers =
{
{"Beyonce", "F"},
{"David Bowie", "M"},
{"Hikaru Utada", "F"},
{"Madonna", "F"},
{"Elton John", "M"},
{"Koji Tamaki", "M"}
};
int females = 0, males = 0;
foreach(string[] arr in singers)
{
if(arr[1] == "F") females++;
else if(arr[1] == "M") males++;
}
In this method, you are essentially using an array of arrays to make iterating through it relatively easier. foreach loop gives each array in the two-dimensional array separately and you can check the element at index 1 to get the gender.
Or if you really have to use string[,], you can do
string[,] singers =
{
{"Beyonce", "F"},
{"David Bowie", "M"},
{"Hikaru Utada", "F"},
{"Madonna", "F"},
{"Elton John", "M"},
{"Koji Tamaki", "M"}
};
int females = 0, males = 0;
for (int i = 0; i < singers.GetLength(0); i++)
{
if(singers[i, 1] == "F") females++;
else if(singers[i, 1] == "M") males++;
}
array.GetLength(int dimension) gives the length of a particular dimension of an array. So we get the length of the first dimension, iterate through that and get the value at index 1 to access the gender values.
I have a class where it has a collection of list. I want to search a parameter inside one of the list. So the location that I found the list, I want to get at the same location at other list in the same class...
How to achieve this?
void Main()
{
var myListCollectionObj = new myListCollection();
Console.WriteLine(myListCollectionObj.firstList);
Console.WriteLine(myListCollectionObj.secondList);
Console.WriteLine(myListCollectionObj.thirdList);
var testFirstList = myListCollectionObj.firstList.Where(x => x == 3); //then i want to get "33", and 333 from secondList and thirdList respectively
Console.WriteLine(testFirstList);
}
class myListCollection
{
public List<int> firstList = new List<int>(){ 1, 2, 3, 4, 5};
public List<string> secondList = new List<string>(){ "11", "22", "33", "44", "55"};
public List<int> thirdList = new List<int>(){ 111, 222, 333, 444, 555};
}
int index = myListCollectionObj.firstList.IndexOf(3);
string elem2;
int elem3;
if (index >= 0 && index < myListCollectionObj.secondList.Length)
elem2 = myListCollectionObj.secondList[index]
if (index >= 0 && index < myListCollectionObj.thirdList.Length)
elem3 = myListCollectionObj.thirdList[index]
You don't need LINQ for that, only List<T>'s own IndexOf() method and indexer property:
int index = myListCollectionObj.firstList.IndexOf(3);
string secondValue = myListCollectionObj.secondList[index];
int thirdValue = myListCollectionObj.thirdList[index];
You may want to add error handling: if 3 is not contained in firstList, an index of -1 is returned by IndexOf().
I guess the best way if there are more than one 3 values would be using simple for loop:
var testFirstList = new List<int>();
var testSecondList = new List<string>();
var testThirdList = new List<int>();
for (var i = 0; i < myListCollectionObj.firstList.Length; ++i) {
if (myListCollectionObj.firstList[i] == 3) {
testFirstList.Add(myListCollectionObj.firstList[i]);
testSecondList.Add(myListCollectionObj.secondList[i]);
testThirdList.Add(myListCollectionObj.thirdList[i]);
}
}
A good guideline is that if you find yourself combining indices and LINQ, you probably have other options available. In this case, a good alternative would be using Zip
This approach lets you combine the 3 collections and act upon the resulting zipped collection as a single entity such that indices are no longer directly required.
var result = firstList.Zip(
secondList.Zip(thirdList,
(b, c) => new { b, c }),
(a, b) => new { Value1 = a, Value2 = b.b, Value3 = b.c })
.Where(x => x.Value1 == 3).ToList();
result.ForEach(v => Console.WriteLine(v));
correct me if i am wrong are you looking for the index of the item you searched in first list and then use the same index to retrieve from other list
If yes
Try this
var testFirstList = myListCollectionObj.firstList.Where(x => x == 3).FirstOrDefault(); //then i want to get "33", and 333 from secondList and thirdList respectively
var index = myListCollectionObj.firstList.IndexOf(testFirstList);
I have a problem with a list that I want to alter, before outputting it back to the client.
For the sake of the question I will post an example of the list and how I need to result to look, because I have looked at Intersect, Except and everything else I could think of, but didn't get the result I am looking for.
Example List:
1, 4, 6, 8
1, 2, 6, 8
2, 4, 6, 8
3, 4, 5, 7
Required Result:
1, 4, 6, 8 //Initial row
-, 2, -, - //Items that have not changed will show as a -
2, 4, -, -
3, -, 5, 7
I really hope I explained it well.
I would be happy to explain this further if needed.
Thanks in advance for the advice, so far I have wrecked my brain over this. ;)
What I tried is too much to type here, so here is what I have so far. Except simply won't do anything with the data because it thinks the rows are different, so they just stay the same.
private List<List<string>> FilterData(List<string[]> datatable)
{
List<string> previousRow = new List<string>();
List<string> currentRow = new List<string>();
List<string> rowDifferences = new List<string>();
List<List<string>> resultingDataset = new List<List<string>>();
foreach (var item in datatable)
{
if (previousRow == null)
{
previousRow = item.ToList();
continue;
}
currentRow = item.ToList();
rowDifferences = currentRow.Except(previousRow).ToList();
resultingDataset.Add(rowDifferences);
}
return resultingDataset;
}
Few things you have to change in your code;
Here is code:
private List<string[]> FilterData(List<string[]> datatable)
{
// List is made of String Array, so need string[] variable not list
string[] previousRow = null ;
string[] currentRow;
string[] rowDifferences ;
// to store the result
List<string[]> resultingDataset = new List<string[]>();
foreach (var item in datatable)
{
if (previousRow == null)
{
previousRow = item;
resultingDataset.Add(previousRow); // add first item to list
continue;
}
currentRow = item;
// check and replace with "-" if elment exist in previous
rowDifferences = currentRow.Select((x, i) => currentRow[i] == previousRow[i] ? "-" : currentRow[i]).ToArray();
resultingDataset.Add(rowDifferences);
// make current as previos
previousRow = item;
}
return resultingDataset;
}
check this dotnetfiddle
private static List<List<string>> FilterData(List<List<string>> datatable)
{
var result = new List<List<string>>();
for(var rowindex = 0; rowindex < datatable.Count; rowindex++)
{
// Clone the string list
var refrow = datatable[rowindex]
.Select(item => (string)item.Clone()).ToList();
result.Add(refrow);
// First row will not get modify anyway
if (rowindex == 0) continue;
var row = result[rowindex];
// previous row of result has changed to "-", so use the original row to compare
var prevrow = datatable[rowindex - 1];
for(var columnindex = 0; columnindex < row.Count; columnindex++)
{
if (row[columnindex] == prevrow[columnindex])
row[columnindex] = "-";
}
}
return result;
}
fiddle
public static List<List<T>> RemoveDuplicates<T>(this List<List<T>> items, T replacedValue) where T: class
{
List<List<T>> ret = items;
items.ForEach(m=> {
var ind = items.IndexOf(m);
if(ind==0)
{
ret.Add(items.FirstOrDefault());
}
else
{
var prevItem = items.Skip(items.IndexOf(m)-1).FirstOrDefault();
var item = new List<T>();
for(var a = 0; a < prevItem.Count; a++)
{
item.Add(prevItem[a] == m[a]? replacedValue : m[a]);
}
ret.Add(item);
}
});
return ret;
}
How to use it:
var items = new List<List<string>>{
new List<string>{ "1", "4", "6", "8" },
new List<string>{ "1", "2", "6", "8" },
new List<string>{ "2", "4", "6", "8" },
new List<string>{ "3", "4", "5", "7" }
};
var result = items.RemoveDuplicates("-");
dotNetFiddle: https://dotnetfiddle.net/n36p64
I have a List<string[]> parsedData.
I have another List<string[]> newData = {n, 1, 2, 3}.
The strings in parsedData seems to be stored the following way:
1. a b c
2. 1 2 3
3. 1 2 3
Which is perfect. When I add the newData to parsedData it becomes like this:
1. a b c
2. 1 2 3
3. 1 2 3
4. n 1 2 3
I'm searching for a way to transpose the newData list and add it in a similar fashion but I have problem getting it to work. Can someone please shed some light on this matter.
This is the code when I parse parsedData:
List<string[]> parsedData = new List<string[]>();
string[] fields;
try
{
TextFieldParser parser = new TextFieldParser(path);
parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(",");
while (!parser.EndOfData)
{
fields = parser.ReadFields();
for (int i = 0; i < fields.Length; i++)
{
if (fields[i] == "NaN")
fields[i] = null;
}
parsedData.Add(fields);
}
parser.Close();
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
return parsedData;
The string[] newData is added to a list in this way:
List<string[]> newData = new List<string[]>();
string[] mCol = mean.meanCol(c, parsedData); // function that returns a string[]
newData.Add(mCol);
I then want to join the two lists as explained above so it looks like this:
a b c n
1 2 3 1
1 2 3 2
1 2 3 3
Okay, I assume you have a text file that looks something like this:
a,b,c
1,2,3
1,2,3
and after you read/parse it, you end up with something that is equal to:
List<string[]> parsedData =
new List<string[]>
{
new []{"a", "b", "c"},
new []{"1", "2", "3"},
new []{"1", "2", "3"}
};
and then you want to be able to add something like:
List<string[]> newData =
new List<string[]>
{
new []{"n", "1", "2", "3"},
new []{"m", "1", "2", "3"},
// ... added more new data
};
Well, first the newData is "turned" 90° and each item has one more data point than the existing ones (a has 1 and 1, while n has 1, 2 and 3).
So even in the ideal way, you'd end up with:
List<string[]> combinedData =
new List<string[]>
{
new []{"a", "b", "c", "n", "m"},
new []{"1", "2", "3", "1", "1"},
new []{"1", "2", "3", "2", "2"},
new []{null, null, null, "3", "3"}
};
And second, you use string[] instead of List<string>, so growing is more complicated.
In any case, a List<string[]> is a suboptimal data structure to express what you want: having several channel names and being able to store several measurements per channel name.
I'd suggest a Dictionary<string, List<string>>, where the key is the channel name and the value, which is a List<string> contains the list of measurements for that channel name.
There are probably easier ways to do it, but one way to get from your List<string[]> to a Dictionary<string, List<string>> could work like:
var transposedData = new Dictionary<string, List<string>>();
var minArrayLength = parsedData.Min(a => a.Length);
for (var index = 0; index < minArrayLength; index++)
{
string key = null;
foreach (var array in parsedData)
{
if (key == null)
{
key = array[index];
transposedData[key] = new List<string>();
}
else
{
transposedData[key].Add(array[index]);
}
}
}
Btw. don't get confused by the var keyword, I like to use that a lot.
Once you have it in this data structure, you can add your newData like this:
foreach (var array in newData)
{
var key = array[0];
transposedData[key] = new List<string>();
// skip the key
for (var index = 1; index < array.Length; index++)
{
transposedData[key].Add(array[index]);
}
}
Now, the question is, are you happy with that, or do you really need a List<string[]> again? If so, you need to transpose it back. Maybe with something like this:
// using a list inside for now for easier adding
var backTranspose = new List<List<string>>();
// determine the max number of measurements for a channel name
var maxLength = transposedData.Values.Max(l => l.Count);
// use one more to include key
for (var valueIndex = 0; valueIndex <= maxLength; valueIndex++)
{
backTranspose.Add(new List<string>());
}
foreach (var kvp in transposedData)
{
var index = 0;
backTranspose[index].Add(kvp.Key);
for (var valueIndex = 0; valueIndex < maxLength; valueIndex++)
{
index++;
if (kvp.Value.Count > valueIndex)
{
backTranspose[index].Add(kvp.Value[valueIndex]);
}
else
{
backTranspose[index].Add(null);
}
}
}
// turn the lists back into arrays
parsedData = new List<string[]>();
foreach (var list in backTranspose)
{
parsedData.Add(list.ToArray());
}
One caveat though, a Dictionary is not ordered. So you might end up with channel names at different positions. But of course, the channel name and the corresponding measurement data will have the same index.
You can use LINQ and Concat to achieve what you need to do.
var allData = parsedData.Concat( newData ).ToList();
I have a List<List<string>> .Each item in these List, will be used to display as columns of a report.
I need to calculate the sum (after converting the string to decimal),of each each column in the report and show it as the footer.
It is not sure, that the number of items in each list will match with other lists.
That means, each item of the lists should be converted and sum up and add in to another list, which will be used to display as the footer row.
Please suggest me, which method would be better to use to achieve this in performance wise.
List<List<string>> test = new List<List<string>>();
List<string> columnTotal = new List<string>();
decimal total = 0;
foreach (var item in test)
{
//Get first element
// decimal dec = Convert.ToDecimal(first element);
// total =total +dec ; ....
//Once first element in all the list has been added,
//columnTotal .add(convert.tostring(total));
//Now get the second element ...so on
}
this is my actual requirement.
Give this a try. I assume you're using a 2D table and not a jagged table.
// Assuming a 2D table and not jagged
List<List<string>> table = new List<List<string>>
{
new List<string> { "1", "2", "3" },
new List<string> { "1", "2", "3" },
new List<string> { "1", "2", "3" },
new List<string> { "2", "3", "4" }
};
List<decimal> footerTotals = new List<decimal>();
for (int i = 0; i < table[0].Count; i++)
{
// Sum the columns
footerTotals.Add(table.Sum(t => decimal.Parse(t[i])));
}
table.ForEach(row => Console.WriteLine(String.Join("\t", row)));
Console.WriteLine(String.Join("\t", footerTotals));
Results:
1 2 3
1 2 3
1 2 3
2 3 4
5 9 13