I have a List of Dictionary<string, object>.
How to find duplicate values in all dictionaries by value?
You can find duplicate values with their occurrences using LINQ.
It gives you duplicate values and its occurrences (index in list and key in dictionary).
var duplicates = dicList
.SelectMany((x, i) => x.Select(p => new { Index = i, Key = p.Key, Value = p.Value }))
.GroupBy(x => x.Value)
.Where(x => x.Count() > 1)
.Select(x => new
{
Value = x.First().Value,
Occurrences = x.Select(o => new { Index = o.Index, Key = o.Key })
});
If you just want duplicate values then use simplified version
var duplicates = listOfDic
.SelectMany(x => x.Values)
.GroupBy(x => x)
.Where(x => x.Count() > 1);
Old classic loop
var uniqueValues = new HashSet<object>();
var duplicateValues = new List<object>();
foreach (var value in yourDictionaries.SelectMany(dict => dict.Values))
{
if (uniqueValues.Add(value) == false)
{
duplicateValues.Add(value);
}
}
SelectMany is a key method for getting all values of all dictionaries.
If you are fan of LINQ you can convert it to the LINQ expression for example by using Aggregate or GroupBy
Use linq for compact code:
List<Dictionary<string, object>> list = new List<Dictionary<string, object>>();
list.SelectMany(dictionary => dictionary.Values).GroupBy(d => d).Where(x => x.Count() >1);
Related
I have the next Dictionary of List:
Dictionary<int, List<int>> links_dict = new Dictionary<int, List<int>>();
This object has these values:
1:{[7,8,3]},2:{[1,3]},3:{[4,8]},4:{[8]}
Is there a LINQ way for remove the same value of all lists within a Dictionary?
For example if I remove '8' from it, the new Dictionary will be:
1:{[7,3]},2:{[1,3]},3:{[4]}
You can just re-project
var results = links_dict.ToDictionary(x => x.Key, x => x.Value.Where(y => y != 8).ToList());
If you need to remove the empty keys, you could check after the fact. It might give you better performance
foreach (var item in results.Where(item => item.Value?.Any() != true))
results.Remove(item.Key);
Or
var results = links_dict.Select(x => (x.Key, x.Value.Where(y => y != 8).ToList()))
.Where(x => x.Item2?.Any() == true)
.ToDictionary(x => x.Item1, x => x.Item2);
Or keeping the original Dictionary
foreach (var key in links_dict.Keys.ToList())
links_dict[key] = links_dict[key].Where(x => x != 8).ToList();
foreach (var item in links_dict.Where(item => item.Value?.Any() != true).ToList())
links_dict.Remove(item.Key);
Using the following linq code, how can I add dense_rank to my results? If that's too slow or complicated, how about just the rank window function?
var x = tableQueryable
.Where(where condition)
.GroupBy(cust=> new { fieldOne = cust.fieldOne ?? string.Empty, fieldTwo = cust.fieldTwo ?? string.Empty})
.Where(g=>g.Count()>1)
.ToList()
.SelectMany(g => g.Select(cust => new {
cust.fieldOne
, cust.fieldTwo
, cust.fieldThree
}));
This does a dense_rank(). Change the GroupBy and the Order according to your need :)
Basically, dense_rank is numbering the ordered groups of a query so:
var DenseRanked = data.Where(item => item.Field2 == 1)
//Grouping the data by the wanted key
.GroupBy(item => new { item.Field1, item.Field3, item.Field4 })
.Where(#group => #group.Any())
// Now that I have the groups I decide how to arrange the order of the groups
.OrderBy(#group => #group.Key.Field1 ?? string.Empty)
.ThenBy(#group => #group.Key.Field3 ?? string.Empty)
.ThenBy(#group => #group.Key.Field4 ?? string.Empty)
// Because linq to entities does not support the following select overloads I'll cast it to an IEnumerable - notice that any data that i don't want was already filtered out before
.AsEnumerable()
// Using this overload of the select I have an index input parameter. Because my scope of work is the groups then it is the ranking of the group. The index starts from 0 so I do the ++ first.
.Select((#group , i) => new
{
Items = #group,
Rank = ++i
})
// I'm seeking the individual items and not the groups so I use select many to retrieve them. This overload gives me both the item and the groups - so I can get the Rank field created above
.SelectMany(v => v.Items, (s, i) => new
{
Item = i,
DenseRank = s.Rank
}).ToList();
Another way is as specified by Manoj's answer in this question - But I prefer it less because of the selecting twice from the table.
So if I understand this correctly, the dense rank is the index of the group it would be when the groups are ordered.
var query = db.SomeTable
.GroupBy(x => new { x.Your, x.Key })
.OrderBy(g => g.Key.Your).ThenBy(g => g.Key.Key)
.AsEnumerable()
.Select((g, i) => new { g, i })
.SelectMany(x =>
x.g.Select(y => new
{
y.Your,
y.Columns,
y.And,
y.Key,
DenseRank = x.i,
}
);
var denseRanks = myDb.tblTestReaderCourseGrades
.GroupBy(x => new { x.Grade })
.OrderByDescending(g => g.Key.Grade)
.AsEnumerable()
.Select((g, i) => new { g, i })
.SelectMany(x =>
x.g.Select(y => new
{
y.Serial,
Rank = x.i + 1,
}
));
I have a dictionary defined as seen here:
Dictionary<int, Dictionary<string, object>> dict = new Dictionary<..>();
And a sample code for adding data:
dict.Add (X, new Dictionary<string, object> ());
dict [X].Add ("Car", CarObject);
dict [X].Add ("Seller", SellerObject);
dict [X].Add ("Key3", Z);
I want to search in the inner dictionary if it contains an object which then contains the following
CarObject.Name = (wildcard)X1(wildcard) of the key "Car" but I just can't seem to get a grasp of how to get into the inner dictionary and then into the object with LINQ in order to search for the value.
This will return all matching KeyValuePair<string, object>.
var query = dict.SelectMany(d => d.Value)
.Where(i => i.Key == "Key1"
&& (
i.Value is CarObject
? ((CarObject)i.Value).Name.Contains("X1")
: false
));
Try the following:
var results = dict[X].Where(x => (x.Value is CarObject) && ((CarObject)x.Value).Name.Contains("X1"));
If you want to get just the value and not the dictionary, and print the values, you can do this:
int X = 0, Z = 1;
dict[X].Add("Key1", CarObject);
dict[X].Add("Key2", SellerObject);
dict[X].Add("Key3", Z);
var results = dict[X].Where(x => (x.Value is CarObject) && ((CarObject)x.Value).Name.Contains("X1")).Select(x => x.Value);
foreach (var str in results)
Console.WriteLine(str);
You can try something like:
dict[X].Where(x => x.Value is CarObject && ((CarObject)x.Value).Name.Contains("X1"));
Or:
dict[X].Values.OfType<CarObject>().Any(x => x.Name.Contains("X1"))
I want to select array values from specific indexes
Now I have this.
var xs = new[] { 11,12,13,14,15 };
var ind = new[] { 3,2,1,0 };
var results = xs.Where((x, idx) => ind.Contains(idx)).ToArray();
The result is {11,12,13,14}
However, I want my result to be ordered by index array which should be {14,13,12,11}
Thank you very much
var results = ind.Select(i => xs[i]).ToArray();
var array = xs.Zip(ind, (x, i) => new Tuple<int, int>(x, i))
.OrderBy(t => t.Item2)
.Select(t => t.Item1)
.ToArray();
I'd like to take an object like this:
SortedList<string, SortedList<int, SortedList<DateTime, double>>> Data
and, for a given 'int' value (key of first nested sorted list), restructure it like this:
SortedList<DateTime, SortedList<string, double>>
or, better yet, this:
SortedList<DateTime, double[]>
where each 'double[]' has as many elements as there are KeyValue pairs in the SortedList.
I'm guessing Linq is the way to go, but can't figure it out. Thanks for any suggestions.
digEmAll beat me to it, but here's the second case in query comprehension syntax:
int desiredInt = //whatever...
var query = from pair in Data
from pair2 in pair.Value
where pair2.Key == desiredInt
from pair3 in pair2.Value
group pair3.Value by pair3.Key into grp
select new { grp.Key, Value = grp.ToArray() };
var result = new SortedList<DateTime, double[]>(query.ToDictionary(a => a.Key, a => a.Value));
int givenKey = ...;
var variant1 = new SortedList<DateTime, SortedList<string, double>>(
Data.Select(pair => new { str = pair.Key, dateValues = pair.Value[givenKey] })
.Where(pair => pair.dateValues != null)
.SelectMany(pair => pair.dateValues.Select(dateValue => new { pair.str, date = dateValue.Key, value = dateValue.Value }))
.GroupBy(pair => pair.date)
.ToDictionary(group => group.Key, group => new SortedList<string, double>(group.ToDictionary(triple => triple.str, triple => triple.value)))
);
var variant2 = new SortedList<DateTime, double[]>(
Data.Select(pair => new { str = pair.Key, dateValues = pair.Value[givenKey] })
.Where(pair => pair.dateValues != null)
.SelectMany(pair => pair.dateValues.Select(dateValue => new { pair.str, date = dateValue.Key, value = dateValue.Value }))
.GroupBy(pair => pair.date)
.ToDictionary(group => group.Key, group => group.Select(triple => triple.value).ToArray())
);
Your transformation is not possible if you use the full resolution of DateTime unless your system regularizes the inserted DateTime value somehow. Even very rapid inserts can occur on a different tick. If you do regularize it then you can get your values as follows:
Dictionary<DateTime, double[]> results = (from d1 in Data
from d2 in d1.Value
where d2.Key == 1
from d3 in d2.Value
group d3 by d3.Key into d3Group
select new {Key = d3Group.Key, Value = (from d4 in d3Group
select d4.Value).ToArray()
}).ToDictionary(element => element.Key, element => element.Value);
SortedList<DateTime, double[]> newSortedList = new SortedList<DateTime, double[]>(results);
The second case is pretty neat:
var dateGroups = Data.SelectMany(x => x.Value)
.SelectMany(x => x.Value)
.GroupBy(x => x.Key)
.ToSortedList(g => g.Key,
g => g.Select(x => x.Value).ToArray());
The first case instead seems wrong, I suspect it should be:
SortedList<DateTime, SortedList<string, double[]>>
If so, the code to get that is the following:
var dict =
(from x in Data
from y in x.Value
from z in y.Value
select new { StrKey = x.Key, IntKey = y.Key, DateKey = z.Key, Value = z.Value })
.GroupBy(x => x.DateKey)
.ToSortedList(g1 => g1.Key,
g1 => g1.GroupBy(x => x.StrKey)
.ToSortedList(g2 => g2.Key,
g2 => g2.Select(y => y.Value).ToArray()));
Where ToSortedList is the following extension:
public static class Exts
{
public static SortedList<TK, TV> ToSortedList<TEl, TK, TV>(
this IEnumerable<TEl> elements,
Func<TEl, TK> keySelector,
Func<TEl, TV> valueSelector)
{
if(elements == null || keySelector == null || valueSelector == null)
throw new ArgumentNullException("An argument of ToSortedList is null");
var dict = new SortedList<TK, TV>();
foreach (var el in elements)
dict.Add(keySelector(el), valueSelector(el));
return dict;
}
}
Phoog's answer is good, but maybe you should consider ILookup instead of SortedList...
ILookup<DateTime, double> result =
(
from pair1 in Data
from pair2 in pair1.Value
where pair2.Key == givenInt
from pair3 in pair2.Value
from theDouble in pair3.Value
select new {theDateTime = pair3.Key, theDouble = theDouble }
)
.ToLookup(x => x.theDateTime, x => x.theDouble);