I am saving multiple tuples that contain strings in a list:
List<Tuple<string, string, string>> ExcelRawImport
What i want to do now, is find the tuple in the list, where the Tuple.Item1 has an specific value.
how should i do this ?
With Linq I would say
var specificValue = "mySpecificValue";
var foundTuple = ExcelRawImport.FirstOrDefault(eri => eri.Item1 == specificValue);
This returns the first Item from your list that matches the specific value. If no matching value is found, foundTuple is null.
If you need all items that match you can use the Where() statement instead.
var foundTuples = ExcelRawImport.Where(eri => eri.Item1 == specificValue).ToList();
Related
I'm currently working on an .NET Framework 4.7.2 application. I'm working on a LINQ query selecting objects from the given data structure:
List<KeyValuePair<int, Dictionary<string, object>>>
It is a list of dynamic objects. I need to select all elements from the list, where the value in the dictionary is true, the key would be IsDummy in this case.
The following image shows the data structure xyz in debug mode:
var result = xyz
.Select(a => a.Value)
.SelectMany(b => b)
.Where(c => c.Key == "IsDummy" && (bool)c.Value == true);
I would like to select a List<KeyValuePair<int, Dictionary<string, object>>> where the value object in the dictionary is of type boolean and has the value true.
Unfortunately my current query doesn't work correctly.
Do you know how to solve this LINQ query? It is a bit tricky because of the KeyValuePair and Dictionary within the list.
Thank you very much!
This should work:
var result = xyz
.Where(kv => kv.Value.TryGetValue("IsDummy", out object value)
&& value is bool b && b); // pattern matching C#7
Non C#7 version:
...
&& value is bool && (bool)value);
You specified:
I would like to select a List<KeyValuePair<int, Dictionary<string,
object>>> where the value object in the dictionary is of type boolean
and has the value true.
The value object? Does this mean that all Dictionaries in the list have only one Value?
Or do you only want those elements from your list that have a Dictionary that has only one value: a Boolean that is true?
Or do you only want those elements from your list that have a Dictionary with at least one Boolean value true?
Or maybe all values should be Booleans with true value?
.
List<KeyValuePair<int, Dictionary<string, object>>> source = ...
var result = source
// keep only those items in the list that have a Dictionary with only one value,
// namely a Boolean that is true
.Where(pair => pair.Value.Count == 1
// pair.Value is a Dictionary;
// pair.Value.Values are the values in the Dictionary
// only keep this item if the one and only value in the dictionary is a Boolean with a value true
&& pair.Value.Values.First().GetType() == typeof(bool)
&& (bool)pair.Value.ValuesFirst());
This can be optimized, using this you'll enumerate the dictionary twice. I leave it like this for improved readability.
2nd specification: Keep only those elements from the list that have a Dictionary that has at least one Boolean with a true value
var result = source
.Where(pair => pair.Value.Values
// keep only the values in the dictionary that are Boolean:
.OfType<bool>()
// keep only the true values
.Where(dictionaryValue => dictionaryValue)
// keep this list item if there is at least one such value in the dictionary
.Any());
With these examples, it will be easy to code the version where all items in the dictionary must be Booleans with a true value
I've defined two lists and now want to filter the escHistory list by Application property matching the filterRIDS RID values.
But stepping through the LINQ that filters out the escHistory I get a return count of zero. Although the list does contain records with Application property values matching those defined in filterRIDS.
Question:
How can you filter list by property value in another list?
This is a basic gist of the filter code:
List<int> filterRIDS = new List<int> { 115841, 200463 };
List<Escalation> escHistory = new List<Escalation>();
//Filter list by RID's matching
escHistory = escHistory.Where(r => r.Application.Contains(filterRIDS.ToString())).ToList<Escalation>();
You swapped the query
escHistory = escHistory.Where(r => filterRIDS.Contains(int.Parse(r.Application))).ToList();
Problem is filterRIDS.ToString() which returns name of List<int> class:
"System.Collections.Generic.List`1[System.Int32]"
Of course you don't have history objects which contain this value in Application field. If you want to check whether Application string contains any string from given list:
escHistory = escHistory
.Where(r => filterRIDS.Any(id => r.Application.Contains(id.ToString())))
.ToList();
I have a dictionary of lists.
var dicAclWithCommonDsEffectivity = new Dictionary<string, List<int>>();
var list1 = new List<int>(){1,2,3};
var list2 = new List<int>(){2,4,6};
var list3 = new List<int>(){3,7,6};
var list4 = new List<int>(){8,7,6};
dicAclWithCommonDsEffectivity.Add("ab",list1);
dicAclWithCommonDsEffectivity.Add("bc",list2);
dicAclWithCommonDsEffectivity.Add("cd",list3);
dicAclWithCommonDsEffectivity.Add("de",list4);
I want to get the keys in dictionary for which atleast one matching value with the current key list.
for key "ab"(first list). I should get: "ab","bc" and "cd".Since these lists contain one of the matching element in {1,2,3}
Is there a way without looping through each item in the list of dictionary value.
Is there a way without looping through each item in the list of dictionary value.
Something has to loop - dictionaries are only designed to look up by key, and you're not doing that other than for the first check.
You can do this fairly easily though:
private IEnumerable<string> GetMatchingKeys(
Dictionary<string, List<int>> dictionary, string key)
{
// TODO: Use TryGetValue if key might not be in dictionary
HashSet<int> elements = new HashSet<int>(dictionary[key]);
return dictionary.Where(pair => pair.Value.Any(x => elements.Contains(x)))
.Select(pair => pair.Key);
}
This uses the fact that Dictionary implements IEnumerable<KeyValuePair<TKey, TValue>> - so the Where clause checks a particular entry by spotting if any of the elements of its value matches any of the elements of the original value. The Select clause then projects the pair to just the key.
If you need to do this a lot and you're concerned about efficiency, another alternative would be to build a second dictionary from int to List<string> - basically a reverse mapping. You'd need to maintain that, but then you could easily fetch all the "original keys" mapping to each of the values corresponding to the given key, and just use Distinct to avoid duplicates.
It's always better to check for existence of the searchKey in the Dictionary before accessing them. Then you can get the associated list in the dictionary for that particular key.
You can also try like this:
string searchKey = "ab";
if (dicAclWithCommonDsEffectivity.ContainsKey(searchKey))
{
var ListToSearch = dicAclWithCommonDsEffectivity[searchKey];
var resultKeys = dicAclWithCommonDsEffectivity.Where(x =>
x.Value.Any(y => ListToSearch.Contains(y)))
.Select(x => x.Key)
.ToList();
}
else
{
// Specified key was not found
}
If what you mean is to visibly (not logically) remove the looping, you could use LINQ with proper Where filter to do that and Select the keys from the Dictionary which have any value element(s) intersect(s) with the selected List (List in the Dictionary with key == "ab") like this:
string key = "ab";
List<int> selectedList = dicAclWithCommonDsEffectivity[key];
var results = dicAclWithCommonDsEffectivity
.Where(x => x.Value.Any(y => selectedList.Contains(y)))
.Select(x => x.Key);
If you want to logically remove the looping too, please consider Mr. Skeet's answer.
Im trying to replace items in a list with the RemoveAll function, but didnt realize that it completely removes the index of the list. Is there a function that can replace objects instead of remove them? I am comparing strings.
Items.RemoveAll(x => commonItems.Any(y => y.ItemName == x.ItemName));
Or maybe once its removed I replace it with another empty index at that same spot?
You could replace RemoveAll with Where to get the records you want to modify first:
var matches = Items.Where(x => commonItems.Any(y => y.ItemName == x.ItemName));
Then just iterate through the results and replace the value:
foreach (var match in matches)
match.ItemName = "N/A";
I have a list like this:
item.Add("a");
item.Add("as");
item.Add("b");
item.Add("fgs");
item.Add("adsd");
How can I find all items that start with (for example) "a"?
This "a" is not some hardcoded string, so I will need a function that do this for each string.
I try with FindAll, but I did not figured out how it works.
Br, Wolfy
If by "start with" you mean the first char, then:
item.FindAll(i => i[0] == 'a');
if you mean a string (may be other than 1 char) then:
item.FindAll(i => i.StartsWith("a"));
If you want a different comparison, such as case-insensitive, locale-based, etc. then do the relevant IndexOf such as:
item.FindAll(i => i.IndexOf("a", StringComparison.CurrentCultureIgnoreCase) == 0);
All of the above can be easily adapted to be use a relevant char or string variable or parameter.
If you don't need the extra properties and methods provided by a list, then it will be more efficient to use Where than FindAll as FindAll creates a new list, and does so in all at once, while Where will enumerate the matching results as it is iterated through.
Or with LINQ
from i in items where i.StartsWith("a") select i;
for NET2.0 you may use this method:
'pattern' is an argument to look for (f.e. "a")
private List<string> FindAll(List<string> list, string pattern)
{ // returns found results
return list.FindAll(delegate(string item)
{
return item.StartsWith(pattern);
});
}
I thought you have another list that contains the startswith criteria strings. Lets call your items "words" and the other list "keywords". So the below query will return what you want.
List<string> words = new List<string>();
words.Add("a");
words.Add("as");
words.Add("b");
words.Add("fgs");
words.Add("adsd");
List<string> keywords = new List<string>();
keywords.Add("a");
keywords.Add("b");
var result = words.FindAll(o =>
keywords.Any(a => o.StartsWith(a))
);
This result has the words that starts with any of the keyword from keywords.
List<string> item = new List<string>();
item.Add("a");
item.Add("as");
item.Add("b");
item.Add("fgs");
item.Add("adsd");
var res1 = item.FindAll(i => i.StartsWith("a"));
var res2 = item.Where(i => i.StartsWith("a"));
Try this
item.FindAll(i => i.Contains("a"));
This will return a List containting only the filtered strings.