C# Elegant method to derive DataRow subset using key column array - c#

I have a DataRow: Row[1, 2, 3, 4, ...]
I also have an array of primary key column names: PKeys[1, 2, ...]
I want an array or list which has an element for each PKeys element containing the value (string) from the matching elements in the DataRow.
Of course I could do this:
List<string> keyVals = new List<string>();
foreach (string PKey in PKeys)
{
keyVals.Add(Row[PKey].ToString());
}
but is there a more elegant method, maybe with LINQ?
Thanks

Try this:
PKeys.Select(key => Row[key].ToString()).ToList()

keyVals.AddRange(from p in PKeys select Row[p].ToString());
Which is the same as
keyVals.AddRange(PKeys.Select(p => Row[p].ToString()));

How about
static IEnumerable<T> GetKeyVals<T>(IEnumerable<T> rows, IEnumerable<T> pKeys)
{
foreach (var PKey in PKeys)
{
yield return Row[PKey];
}
}
So you could do this, using deferred execution.
var keysVals = GetKeyVals(Row, PKeys);
This is, in practice, the same as
var keysVals = PKeys.Select(pkey => return Row[pkey]);
I'm not sure I understand your rush to IList<string>.

Related

How to use Linq and lambda expressions on a Dictionary<string, List<T>> to a specify its order based on Key

So I have a Dictionary with string keys, and the value is a List of objects. Each object in each List has a property value which is equal to that List's associated key. In other words, the Dictionary is grouping objects by property value via the key. For example, let's say we have,
Dictionary<string, List<Animal>> GroupedByClass = new Dictionary<string, Animal>();
Where Animal is an object which contains a string property named "ClassType" which has valid options of "Mammal", "Reptile", or "Amphibian", etc.
The Animal class could also have string property named "Species" which more uniquely defines each object in the Dictionary.
A pseudocode description of the contents of the Dictionary could be:
<"Mammal", List<Animal>>
where the Animals in the list have Species "Dog", "Cat"
<"Reptile", List>
where the Animals in the list have Species "Snake", "Lizard", and "Turtle"
<"Amphibian", List>
where the Animals in the list have Species "Salamander" and "Frog"
I want to rearrange this Dictionary by the key value such that the values with a key of "Reptile" are first, then "Amphibian", and then finally "Mammal". Note that I do not want to sort this based on alphabetical order, I want to specify my own order.
I know I could solve this problem by simply iterating through the Dictionary a few times, extracting only the items with the right key. For example, I could do it like this,
Dictionary<string, List<Animal>> temp = new Dictionary<string, List<Animal>>();
foreach(KeyValuePair<string, List<Animal>> item in GroupedByClass)
{
if(item.Key == "Reptile")
{
temp.Add(item.Key, item.Value);
}
}
foreach(KeyValuePair<string, List<Animal>> item in GroupedByClass)
{
if(item.Key == "Amphibian")
{
temp.Add(item.Key, item.Value);
}
}
foreach(KeyValuePair<string, List<Animal>> item in GroupedByClass)
{
if(item.Key == "Mammal")
{
temp.Add(item.Key, item.Value);
}
}
return temp;
However, this seems inelegant, and I was wondering if there was a better answer for this problem using Linq queries and lambda expressions.
This should be close (with some syntax errors):
var order = new [] {"Reptile","Amphibian","Mammal"};
var elems = dict.OrderBy(x=>order.IndexOf(x.Key));
if you want to flatten the results, then you can use SelectMany:
var order = new [] {"Reptile","Amphibian","Mammal"};
var elems = dict.SelectMany(x=>x).OrderBy(x=>order.IndexOf(x.Species));
Dictionary<string, List<Animal>> temp = new Dictionary<string,List<Animal>>();
(new List<string>() {"Reptile","Amphibian","Mammal"}).ForEach(x => temp.Add(x, GroupedByClass[x]));
You could define an enumeration and have it be your defining order.
enum Animal : int
{
Reptile = 0,
Amphibian = 1,
Mammal = 2
}
Note, since you have simple strings this works and is straight forward. If however you end up with strings that have spaces you can use the DescriptionAttribute of the enumeration and go between it and the actual enumeration.
Enumeration with Display String
By using an enumeration over the string you can do many things, but of course order by it using the integers you assiged.

How to get Distinct keys of all child dictionary elements of all parent dictionary values

I have a dictionary like this...
Dictionary<string, Dictionary<string, double>>
How to get the list of all Distinct or unique child dictionary keys from all dictionaries of all parent dictionary values (parent dictionary values is nothing but child dictionaries)?
which is the fastest way of doing this in C#?
It's really easy using LINQ:
var result = myDict.Values.SelectMany(x => x.Keys)
.Concat(myDict.Keys)
.Distinct()
.ToList();
but even without LINQ it's super easy when you use HashSet<string>:
var set = new HashSet<string>();
foreach(var outerItem in myDict)
{
set.Add(outerItem.Key);
foreach(var innerKey in item.Value.Keys)
{
set.Add(innerKey);
}
}
HashSet<T> will only keep distinct items, so adding the same string twice won't make any difference.
PS. Next time you should try writing the code first, and ask question when you run into issue you can't overcome by yourself. Stack Overflow is not 'I want code, give me code' kind of site.
Then you need to call SelectMany() on Values property of your dictionary and then use Distinct() to get distinct elements from a sequence by using the default equality comparer.
var res = myDict.Values.SelectMany(x => x.Keys).Distinct().ToList();
This code creates a Dictionary with string keys and double values.
Dictionary<string, double> d = new Dictionary<string, double>()
{
};
// Store keys in a List
List<string> list = new List<string>(d.Keys);
// Loop through list
foreach (string k in list)
{
//From here you can choose distinct key
}
If I'm reading this right:
IEnumerable<string> uniqueChildKeys = dictOfDicts
.SelectMany(d => d.Value.Keys)
.Distinct();

What is the best way to trim a list?

I have a List of strings. Its being generated elsewhere but i will generate it below to help describe this simplified example
var list = new List<string>();
list.Add("Joe");
list.Add("");
list.Add("Bill");
list.Add("Bill");
list.Add("");
list.Add("Scott");
list.Add("Joe");
list.Add("");
list.Add("");
list = TrimList(list);
I would like a function that "trims" this list and by trim I want to remove all items at the end of the array that are blank strings (the final two in this case).
NOTE: I still want to keep the blank one that is the second item in the array (or any other one that is just not at the end) so I can't do a .Where(r=> String.isNullOrEmpty(r))
I would just write it without any LINQ, to be honest- after all, you're modifying a collection rather than just querying it:
void TrimList(List<string> list)
{
int lastNonEmpty = list.FindLastIndex(x => !string.IsNullOrEmpty(x));
int firstToRemove = lastNonEmpty + 1;
list.RemoveRange(firstToRemove, list.Count - firstToRemove);
}
If you actually want to create a new list, then the LINQ-based solutions are okay... although potentially somewhat inefficient (as Reverse has to buffer everything).
Take advantage of Reverse and SkipWhile.
list = list.Reverse().SkipWhile(s => String.IsNullOrEmpty(s)).Reverse().ToList();
List<T> (not the interface) has a FindLastIndex method. Therefore you can wrap that in a method:
static IList<string> TrimList(List<string> input) {
return input.Take(input.FindLastIndex(x => !string.IsNullOrEmpty(x)) + 1)
.ToList();
}
This produces a copy, whereas Jon's modifies the list.
The only solution I can think of is to code a loop that starts at the end of the list and searches for an element that is not an empty string. Don't know of any library functions that would help. Once you know the last good element, you know which ones to remove.
Be careful not to modify the collection while you are iterating over it. Tends to break the iterator.
I always like to come up with the most generic solution possible. Why restrict yourself with lists and strings? Let's make an algorithm for generic enumerable!
public static class EnumerableExtensions
{
public static IEnumerable<T> TrimEnd<T>(this IEnumerable<T> enumerable, Predicate<T> predicate)
{
if (predicate == null)
{
throw new ArgumentNullException("predicate");
}
var accumulator = new LinkedList<T>();
foreach (var item in enumerable)
{
if (predicate(item))
{
accumulator.AddLast(item);
}
else
{
foreach (var accumulated in accumulator)
{
yield return accumulated;
}
accumulator.Clear();
yield return item;
}
}
}
}
Use it like this:
var list = new[]
{
"Joe",
"",
"Bill",
"Bill",
"",
"Scott",
"Joe",
"",
""
};
foreach (var item in list.TrimEnd(string.IsNullOrEmpty))
{
Console.WriteLine(item);
}

Removing items from collection

I have a list of ids, and the items with these ids shall be removed from a Collection.
foreach(string id in list) {
myitemcollection.Remove(id); // This does not exist. How would I implement it?
}
Unfortunately, "Remove" takes a complete item, which I don't have, and "RemoveAt" takes an index, which I don't have either.
How can I achieve this? Nested loops will work, but is there a better way?
One way would be to use linq:
foreach(string id in list) {
//get item which matches the id
var item = myitemcollection.Where(x => x.id == id);
//remove that item
myitemcollection.Remove(item);
}
If mycollection is also a list of ints, you could use
List<int> list = new List<int> {1,2,3};
List<int> myitemcollection = new List<int> {1,2,3,4,5,6};
myitemcollection.RemoveAll(list.Contains);
If it is a custom class, lets say
public class myclass
{
public int ID;
}
you could use
List<int> list = new List<int> {1,2,3};
List<myclass> myitemcollection = new List<myclass>
{
new myclass { ID = 1},
new myclass { ID = 2},
new myclass { ID = 3},
new myclass { ID = 4},
new myclass { ID = 5},
new myclass { ID = 6},
};
myitemcollection.RemoveAll(i => list.Contains(i.ID));
List.RemoveAll Method
Removes all the elements that match the conditions defined by the
specified predicate.
Try using linq:
var newCollection = myitemcollection.Where(x=> !list.Contains(x.ID));
Please note that:
This assumes that your Item collection has data member called ID.
This is not the best performance wise...
If I understood your question rightly, try the below code snip
foreach (string id in list)
{
if (id == "") // check some condition to skip all other items in list
{
myitemcollection.Remove(id); // This does not exist. How would I implement it?
}
}
If this is not good enough. Make your question more clear to get exact answer
In terms of theory, you are dealing with a matter called closure.Within a loop (or for), you should make a copy of your list (or array or what you are iterating) in every way (that is mentioned differently by guys), mark those you want to remove and then deal with them out of the loop.

BinarySearch in two dimensional list

I have dimensional list:
List<List<string>> index_en_bg = new List<List<string>>();
index_en_bg.Add(new List<string>() { word1, translation1 });
index_en_bg.Add(new List<string>() { word2, translation2 });
index_en_bg.Add(new List<string>() { word3, translation3 });
I would do binary search by the first column (words), something like this:
int row = index_en_bg.BinarySearch(searchingstr);
but it works only for a one-dimensional list. How would I extend it to work for two-dimensional lists in my case? I don't want to use Dictionary class.
In this case you need to provide your own customer IComparer-implementing comparator
public class Comparer: IComparer<IList<string>>
{
public int Compare(IList<string> x, IList<string> y)
{
// base the comparison result on the first element in the respective lists
// eg basically
return x[0].CompareTo(y[0]);
}
And you'll call it like this, offering a List where only the field you're searching is filled in.
int row = index_en_bg.BinarySearch(new List<string>() {searchingstr},new Comparer());
Well as far as I understand you should use Dictionary<K,V> instead, this way:
// 1 creating the dictionary
var dic = new Dictionary<string, string>();
dic["word1"] = "translation1";
dic["word2"] = "translation2";
dic["word3"] = "translation3";
// 2 finding a translation
var trans = dic["word1"];
And Dictionary<K,V> is really performant.
But if you insist on using BinarySearch you can implement IComparer<List<string>> and pass it to the function.
As you always search using the first item of the list you could use dictionary too.
var d = Dictionary<string, List<string>>();
as answered previously it's preforms much better than List.

Categories

Resources