I have a list as below. I would like to retrieve the indexes of all the items which have the value 1.
List<int> listFilter = new List<int>();
listFilter.Add(1);
listFilter.Add(0);
listFilter.Add(0);
listFilter.Add(1);
I should be getting 0 and 3 for the sample data above.
The code below gives me an object of [value, index] pair. How do I modify this to just output a list which has only the indexes.
var val = listFilter.Select((value, index) => new { Value = value, Index = index }).Where(item => item.Value == 1).ToList();
Thanks
Regards,
Balan Sinniah
The problem is that in the initial Select clause you returned an anonymous type. To get back out the value you need an additional Select later on to filter back to that value.
var val = listFilter
.Select((value, index) => new { Value = value, Index = index })
.Where(item => item.Value == 1)
.Select(item => item.Index)
.ToList();
Related
I am having a list of string which contains some value and I want to compare values of 2 positions from list and remove matching items from list.
Code :
var list = new List<string>();
list.Add("Employee1");
list.Add("Account");
list.Add("100.5600,A+ ,John");
list.Add("1.00000,A+ ,John");
list.Add("USA");
Now i want to compare 2nd and 3rd position :
list.Add("100.5600,A+ ,John");
list.Add("1.00000,A+ ,John");
Compare above 2 records and remove matching records like below:
Expected output :
list.Add("100.5600");
list.Add("1.00000");
This is how i am trying to do :
var source = list[2].Split(',').Select(p => p.Trim());
var target = list[3].Split(',').Select(p => p.Trim());
var result = source.Except(target);
But the problem is I am only getting 100.5600 as output.
Is it possible to compare and update non matching records in existing list?
How about this "beauty"
var list = new List<string>();
list.Add("Employee1");
list.Add("Account");
list.Add("100.5600,A+ ,John");
list.Add("1.00000,A+ ,John");
list.Add("USA");
//prepare the list, I decided to make a tuple with the original string in the list and the splitted array
var preparedItems = list.Select(x => (x, x.Split(',')));
//group the prepared list to get matching items for the 2nd and 3rd part of the split, I therefor used .Skip(1) on the previously prepared array
var groupedItems = preparedItems.GroupBy(x => string.Join(",", x.Item2.Skip(1).Select(y => y.Trim())));
//"evaluate" the group by saying if the items in the group is > 1 only use the first part of the prepared array and if it doesnt have more than one entry use the orignal string
var evaluatedItems = groupedItems.SelectMany(x => x.Count() > 1 ? x.Select(y => y.Item2[0]) : x.Select(y => y.Item1));
//replace the orignal list with the new result
list = evaluatedItems.ToList();
Edit - preserve original order:
//extended the prepare routine with a third part the index to Keep track of the ordering of the original list
//so the tuple now consits of 3 parts instead of 2 - ([item], [index], [splittedArray])
var preparedItems = list.Select((x, i) => (x, i, x.Split(',')));
//changed to use Item3 intead of Item2 - since the Array now is on third position
var groupedItems = preparedItems.GroupBy(x => string.Join(",", x.Item3.Skip(1).Select(y => y.Trim())));
//instead of returning the simple string here already, return a tuple with the index (y.Item2) and the correct string
var evaluatedItems = groupedItems.SelectMany(x => x.Count() > 1 ? x.Select(y => (y.Item2, y.Item3[0])) : x.Select(y => (y.Item2, y.Item1)));
//now order by the new tuple x.Item1 and only return x.Item2
var orderedItems = evaluatedItems.OrderBy(x => x.Item1).Select(x => x.Item2);
list = orderedItems.ToList();
//one-liner - isn't that a beauty
list = list.Select((x, i) => (x, i, x.Split(','))).GroupBy(x => string.Join(",", x.Item3.Skip(1).Select(y => y.Trim()))).SelectMany(x => x.Count() > 1 ? x.Select(y => (y.Item2, y.Item3[0])) : x.Select(y => (y.Item2, y.Item1))).OrderBy(x => x.Item1).Select(x => x.Item2).ToList();
You may get it easily by checking if items in one is not contained in the other:
var result = source.Where(x => !target.Contains(x));
To update your old list:
var source = string.Join(",", source.Where(x => !target.Contains(x)));
Some days ago I asked for a way to find columns with null values in a row list with Linq. Now I need to get the index of every found item and add it to a list and then show in a warning message later.
These are my row list and my null columns list.
var rowList = tablaExcel.AsEnumerable().Select(x => x.ItemArray).ToList();
var nullValues = rowList.Where(x => x.Any(y => y == null || y == DBNull.Value)).ToList();
How can I get the index of any found item in the rowList.Where()? Just in case, I need the index of the rowList item, not of the nullValues item.
Thanks in advance.
use this code:
var indexes = rowList.Select((v, i) => new { v, i })
.Where(x => x.v.Any(y => y == null || y == DBNull.Value))
.Select(x => x.i);
This question already has answers here:
How to convert array to dictionary
(2 answers)
Closed 5 years ago.
I have an Object array of my class (Item) like below,
class Item
{
int id;
int value;
bool isSelected;
}
Item itemArr[] = new Item [MAXCOUNT];
To retrieve the selected Item ids and store into list, I am using below code
List<int> listOfItems = new List<int>();
listOfItems.AddRange(itemArr.Where(p => (p.IsSelected)
.Select(p => p.ID)).ToArray());
I have one more Dictionary which indicates item id as key and item value as value,
Dictionary<int,int> itemidValueMap = new Dictionary<int,int>();
How to get item id and value pair and store it into this dictionary?
This question is not duplicate. I need to select only the elements which satisfies the condition and store only them in dictionary. But previous question says about adding all the elements into dictionary.
To get the selected IDs your query should look like this:
List<int> selectedIDs = itemArr.Where(item => item.IsSelected).Select(item => item.id).ToList();
Note that the result is a List<int>, not a List<Item>.
To get your dictionary try this:
var idToValue = itemArr.ToDictionary(item => item.id, item => item.value);
This only works if your IDs are unique. If they are not, you'll need to group them, but I don't know how you want to aggregate the values of items with the same ID.
If you want that dictionary only for selected items, you simply insert the Where clause again:
var idToValue = itemArr.Where(item => item.IsSelected).ToDictionary(item => item.id, item => item.value);
To construct the dictionary use ToDictionary:
var dictionary = itemArr.Where(p => p.IsSelected)
.ToDictionary(key => key.id, value => value.value);
If you have the same id a few times it will cause an exception (keys are not unique) so use ToLookup or first GroupBy and then ToDictionary.
var lookup = itemArr.Where(p => p.IsSelected)
.ToLookup(key => key.id, value => value.value);
var dictionary = itemArr.Where(p => p.IsSelected)
.GroupBy(i => i.id)
.ToDictionary(key => key.Key, value => value.Select(i => i.value));
As a side note you can populate the ID list a bit nicer:
var listOfItems = itemArr.Where(p => p.IsSelected).Select(p => p.ID).ToList();
You need to change this
listOfItems.AddRange(itemArr.Where
(p => (p.IsSelected).Select(p => p.ID)).ToArray());
to
listOfItems.AddRange(itemArr.Where
(p => p.IsSelected).ToArray());
then
Dictionary<int,int> itemidValueMap = listOfItems.ToDictionary(item => item.id,
item => item.value)
I have a string comma separated list of some data. I have another list of strings of keywords that i want to search for in the first list. I want to have returned to me the index of all the elements in the first list that do no contain any of the keywords in the second list. For example:
List 1:
Student,101256,Active
Professor,597856,Active
Professor,697843,Inactive
Student,329741,Active
Student,135679,Inactive
Student,241786,Inactive
List 2:
697843
241786
My query on List 1 should be, give me all the index of all the elements that do not contain any of the elements of list 2. Therefore, the return list of indices should be 0,1,3,4. Is there any way to accomplish this?
Thanks in advance!
Edit: This is my try:
List<int> index = list1
.Select((s, i) => new { s, i })
.Where(e => !list2.Contains(e.s))
.Select(e => e.i).ToList();
You will need to reference System.Linq, this has now been edited to include the !Student filter
var list1 = new List<string> {
{"Student,101256,Active"},
{"Professor,597856,Active"},
{"Professor,697843,Inactive"},
{"Student,329741,Active"},
{"Student,135679,Inactive"},
{"Student,241786,Inactive"}
};
var list2 = new List<string> {{"697843"}, {"241786"}};
var result = list1
.Select((item,i)=> new {index=i,value=item})
.Where(item => !item.value.StartsWith("Student"))
.Where(item => !item.value.Split(',').Any(j => list2.Contains(j)))
.Select(item=>item.index)
.ToList();
The first select extracts the index before filtering, the pre-edited version calculated the index after the filter and so was incorrect.
I have a List<bool>. I need to get the indexes of top n items where item value = true.
For example the following list items(bool)
10011001000
TopTrueIndexes(3) = The first 3 indexes where bits are true are 0, 3, 4
TopTrueIndexes(4) = The first 4 indexes where bits are true are 0, 3, 4, 7
How can I write a lambda for this?
Well, assuming you have some easily-identifiable condition, you can do something like this, which will work for any IEnumerable<T>:
var query = source.Select((value, index) => new { value, index })
.Where(x => x.value => Condition(value))
.Select(x => x.index)
.Take(n);
(Obviously fill in the appropriate bit of the Where clause. If it's just a List<bool> it may just be x => x.value.)
The important bits are that you use the overload of Select to get index/value pairs before the Where, and then another Select to get just the indexes after the Where... and use Take to only get the first n results.
There's an overload of Select where the lambda gets two parameters: the index and the element. So you can just take the indices where the value is true, supplying a sentinel (here, -1) for the ones you don't want. Then filter out the sentinels and take how many you want:
bool[] bools = ...;
var indices = bools.Select((val, ix) => val ? ix : -1).Where(i => i >= 0).Take(n);
This should probably do it.
IEnumerable<bool> GetItemsInList(IEnumerable<bool> list, int count) {
int ind = 0;
return list.Select(itm => new {i = ind++, v = itm}).Where(itm => itm.v).Take(count).Select(itm => itm.i);
}
Here how it goes:
Select source + its index
Add condition to the where clause (the source of the where clause now contains the original source + index)
Select the index (the index returned here is the original index from the original source)
var indexes = inputList.Select((input, index) => new { input, index }).Where(a => condition(a.input)).Select(a => a.index);