Dictionary<string, List<Dictionary<string,string>>> query using linq - linq

I have the below dictionary
Dictionary<string,string> q1=new Dictionary<string,string>
{
{"h1","name1"},{"h2","name2"}
};
Dictionary<string,string> q2=new Dictionary<string,string>
{
{"h1","name12"},{"h2","name23"}
};
Dictionary<string,string> q3=new Dictionary<string,string>
{
{"h1","name123"},{"h2","name234"}
};
List<Dictionary<string,string>> m1 = new List<Dictionary<string,string>> { q1,q2,q3 };
Dictionary<string, List<Dictionary<string,string>>> mhi = new Dictionary<string, List<Dictionary<string,string>>>();
mhi.Add("x1", m1);
I need to return a list which has the values name1,name12,name123 using linq.
I am aware of normal method which works for me. But I am curious to know how to implement this using linq

Try this:
var q1 = new Dictionary<string, string> {
{"h1", "name1"},
{"h2", "name2"}
};
var q2 = new Dictionary<string, string> {
{"h1", "name12"},
{"h2", "name23"}
};
var q3 = new Dictionary<string, string> {
{"h1", "name123"},
{"h2", "name234"}
};
var m1 = new List<Dictionary<string, string>> { q1, q2, q3 };
//Using LINQ
List<string> result = (from dictionary in m1
from keyValuePair in dictionary
where keyValuePair.Key == "h1"
select keyValuePair.Value).ToList();
//result = name1,name12,name123
//without linq
var result2 = new List<string>();
foreach(var dictionary in m1)
foreach(var keyValuePair in dictionary)
if(keyValuePair.Key == "h1")
result2.Add(keyValuePair.Value);
Edit:
The from clause specifies the data source, the where clause applies the filter, and the select clause projects each element of the sequence into a new form.
Linq queries are not executed until we iterate through it. (Here .ToList() is doing that). It's like a blueprint which specifies how the information is returned when executed(iterated).
Lets examine each statement separately:
from dictionary in m1 - This is much like foreach(var dictionary in m) except that it doesn't iterate (Because its a blueprint). It specifies which source we are iterating through (m1) and the variable to assign to each member (dictionary that is. We know that it will be of type Dictionary<String, String>)
from keyValuePair in dictionary - Here we use the dictionary variable created from the previous statement. The type of keyValuePair will be KeyValuePair<string,string> because we will be "iterating" through a Dictionary<string,string> when the query is executed.
where keyvaluePair.Key == "h1" - This filters out the keyValuePairs from the previous statement whose Key property equals "h1".
Now that we filtered out the KeyValuePairs, we can select their Value property. This "projects" the filtered out KeyValuePair sequence to the new type IEnumerable<string>
Finally, ToList method executes the query to get the results.

Related

how to convert var to dictionary and access var using foreach loop

i have a dictionary defined as follows:
Dictionary<string, int> Controls = new Dictionary<string, int>();
using the following code i am putting keys which have similar value into var
var result = (from p in Controls
group p by p.Value into g
where g.Count() > 1
select g);
But neither i am able to convert 'result' into dictionary again or nor i am able to access item inside 'result'
i tried this code but
foreach (System.Linq.Lookup<int, KeyValuePair<string, int>> Item in result)
{
}
Plz help.
try this:
var dict = result.ToDictionary(x => x.Key, x => x.Select(y => y.Key).ToList())
and access it like
foreach(var item in dict)
BTW, there's no type var. It's just instruction for the compiler to determine type for variable, but it's strongly typed. In your case, I think, it would be IEnumerable<IGrouping<TKey, TSource>>. Actually you can access result like this too:
foreach(var item in result)
{
// item is type Lookup<int, KeyValuePair<string, int>>.Grouping
// you can go through item like
foreach(var i in item)
{
}
// or convert it ToList()
var l = item.ToList()
// l is type List<KeyValuePair<string, int>>
}

Linq query Group By multiple columns

I have a array of string say:
String[] Fields=new String[]{RowField,RowField1}
In which I can use the below query to get the values by specifying the values is query i.e RowField and RowField1:
var Result = (
from x in _dataTable.AsEnumerable()
select new
{
Name = x.Field<object>(RowField),
Name1 = x.Field<object>(RowField1)
})
.Distinct();
But if suppose I have many values in the Array like:
String[] Fields= new String[]
{
RowField,
RowField1,
RowField2,
.......
RowField1000
};
How can I use the query here without specifying each of the rowfield in the query?
How can i iterate through the array items inside the LINQ?
According to some suggestions in LINQ query and Array of string I am trying to get the result using the code below.
var result = (from row in _dataTable.AsEnumerable()
let projection = from fieldName in fields
select new {Name = fieldName, Value = row[fieldName]}
select projection.ToDictionary(p=>p.Name,p=>p.Value))
.Distinct();
But the problem is it does not return the distinct values.Any ideas?
Start with distinct DataRows by using this overload of Distinct():
_dataTable.AsEnumerable().Distinct(new DataRowEqualityComparer())
Where DataRowEqualityComparer is:
public class DataRowEqualityComparer : IEqualityComparer<DataRow>
{
public bool Equals(DataRow x, DataRow y)
{
return x.ItemArray.SequenceEqual(y.ItemArray);
}
public int GetHashCode(DataRow obj)
{
return string.Join("", obj.ItemArray).GetHashCode();
}
}

linq select from database where ID in an ArrayList

I have an array-list that contains some UserID.
I need a query like this:
vat tmp= users.select(a=> a.UserID in (arraylist));
what can I do?
If it's actually in an ArrayList, you should create a List<T> or array first. Then you can use Contains:
// Use the appropriate type, of course.
var ids = arraylist.Cast<string>().ToList();
var tmp = users.Select(a => ids.Contains(a.UserID));
While using Contains on the plain ArrayList may well compile, I would expect it to fail at execution time, assuming users is an IQueryable<>.
List<long> list =new List<long>();
var selected = from n in users where list.Contains(n.ID) select n ;
OR
var selected = users.Where(a=> list.Contains(a.ID)).ToList();
This is the solution I used.
public static IEnumerable<SettingModel> GetSettingBySettingKeys(params string[] settingKey)
{
using (var db = new BoxCoreModelEntities())
{
foreach (var key in settingKey)
{
var key1 = key;
yield return Map(db.Settings.Where(s => s.SettingKey == key1).First());
}
}
}

Need help with formulating LINQ query

I'm building a word anagram program that uses a database which contains one simple table:
Words
---------------------
varchar(15) alphagram
varchar(15) anagram
(other fields omitted for brevity)
An alphagram is the letters of a word arranged in alphabetical order. For example, the alphagram for OVERFLOW would be EFLOORVW. Every Alphagram in my database has one or more Anagrams. Here's a sample data dump of my table:
Alphagram Anagram
EINORST NORITES
EINORST OESTRIN
EINORST ORIENTS
EINORST STONIER
ADEINRT ANTIRED
ADEINRT DETRAIN
ADEINRT TRAINED
I'm trying to build a LINQ query that would return a list of Alphagrams along with their associated Anagrams. Is this possible?
UPDATE: Here's my solution based on the suggestions below! Thanks all!
using (LexiconEntities ctx = new LexiconEntities())
{
var words = ctx.words;
var query =
from word in words
where word.alphagram == "AEINRST"
group word by word.alphagram into alphagramGroup
select new { Alphagram = alphagramGroup.Key, Anagrams = alphagramGroup };
foreach (var alphagramGroup in query)
{
Console.WriteLine("Alphagram: {0}", alphagramGroup.Alphagram);
foreach (var anagram in alphagramGroup.Anagrams)
{
Console.WriteLine("Anagram: {0}", anagram.word1);
}
}
}
var list = anagrams.Select(
a => new {
Alphagram = a.ToCharArray().OrderBy(s => s).ToString(),
Anagram = a
}).toList();
A totally new answer...
You seem to need a groupby query look at How to: Group Data (Entity Framework).
this should accomplish what you want...
I did a testy with LINQ and this works...
var words = new List<Word>()
{
new ConsoleApplication1.Word("EINORST", "NORITES"),
new ConsoleApplication1.Word("EINORST", "OESTRIN"),
new ConsoleApplication1.Word("EINORST", "STONIER"),
new ConsoleApplication1.Word("ADEINRT", "ANTIRED"),
new ConsoleApplication1.Word("ADEINRT", "DETRAIN"),
new ConsoleApplication1.Word("ADEINRT", "TRAINED")
};
var q = words.GroupBy(w => w.Alphagram).Select(w => new { Alphagram = w.Key, Anagrams = w.Select(p => p.Anagram).ToList() }).ToList();
foreach (var item in q)
{
Console.WriteLine("Alphagram : {0}, Anagrams = {1}", item.Alphagram, String.Join(",", item.Anagrams));
}
var words = new List<Words>()
{
new Words("EINORST", "NORITES"),
new Words("EINORST", "OESTRIN"),
new Words("EINORST", "STONIER"),
new Words("ADEINRT", "ANTIRED"),
new Words("ADEINRT", "DETRAIN"),
new Words("ADEINRT", "TRAINED")
};
var result = words.GroupBy(w => w.Alphagram, w => w.Anagram)
.Select(w => new {
Alphagram = w.Key,
Anagrams = w.Where(p => w.Key.ToCharArray().SequenceEqualUnOrdered(p.ToCharArray())).ToList()
}
)
.ToList();
public static bool SequenceEqualUnOrdered<T>(this IEnumerable<T> first, IEnumerable<T> second)
{
return new HashSet<T>(first).SetEquals(second);
}
Is it what you are looking for? It is LINQ to Objects. You may want to use LINQ-to-SQL or LINQ-to-Entites to fetch your records into your objects and then use the above-mentioned LINQ-to-Objects query over the already-fetched object collection.

LINQ: IEnumerable<KeyValuePair<SomeType, IEnumerable<OtherType>>> selection

How do I transform this IEnumerable<KeyValuePair<MyType, IEnumerable<OtherType>>> into new
sequence of the same type, except I just want First() that is in the value (IEnumerable<OtherType>). Something like this (pseudo code):
var toReturn = from kv in source
let k = new KeyValuePair(kv.Key, kv.Value.First())
select k;
I'm unsure if you want the Value in the new KeyValuePair to be an enumerable of that type or a single element. Here's both versions
IEnumerable version
var toReturn = source.Select(x => new KeyValuePair<SomeType,IEnumerable<SomeOtherType>>(x.Key, x.Value.Take(1));
Non-Enumerable Version
var toReturn = source.Select(x => new KeyValuePair<SomeType,SomeOtherType>(x.Key,x.Value.First());
All you're missing is the type of KeyValuePair to use. You could use Jared's lambda expression version, or if you like the query expression syntax:
var toReturn = from kv in source
select new KeyValuePair<MyType, OtherType>(kv.Key,
kv.Value.First());
If you don't want to explicitly specify the type arguments, you could create your own helper class and use type inference:
// Non-generic helper class.
public static class KeyValuePair
{
public static KeyValuePair<TKey, TValue> Of(TKey key, TValue value)
{
return new KeyValuePair<TKey, TValue>(key, value);
}
}
at which point your query becomes:
var toReturn = from kv in source
select KeyValuePair.Of(kv.Key, kv.Value.First());
or
var toReturn = source.Select(kv => KeyValuePair.Of(kv.Key, kv.Value.First());
EDIT: Oops - I think I'd misread your question as well. If you want it to be of the exact same type, i.e. with the value being enumerable too, just use Take(1) instead of First():
var toReturn = source.Select(kv => KeyValuePair.Of(kv.Key, kv.Value.Take(1));
(Isn't type inference lovely? :)
var toReturn = source
.ToDictionary(
kvp => kvp.Key,
kvp => kvp.Value.Take(1)
);
Why do you want to get a collection of the same type? When you just have the first element, you don't need a collection (IEnumerable<OtherType>) but a single value (OtherType).
This (like the one you posted) should be correct (you will just need to add generic parameters for the KeyValuePair)
var toReturn = from kv in source select new KeyValuePair<SomeType, OtherType>(kv.Key, kv.Value.First());
If you really want to get a collection of the same type, write
var toReturn = from kv in source select new KeyValuePair<SomeType, IEnumerable<OtherType>>(kv.Key, new [] { kv.Value.First() });
Note: You don't need to give explicit type arguments to the KeyValuePair when you wrap this into a generic function.
KeyValuePair<TKey, TValue> Pair<TKey, TValue>(TKey key, TValue value) {
return new KeyValuePair<TKey, TValue>(key, value);
}
//
var foo = Pair(1, "Hello");

Resources