Build a new dictionary with concatenated duplicated keys based on values - c#

How to concatenate and remove duplicates in dictionary like this:
Item1: Key=1, Value=test1
Item2: Key=2, Value=test2
Item3: Key=3, Value=test1
Item4: Key=4, Value=test3
Item5: Key=5, Value=test4
To build a new Dictionary like this:
Item1: Key=1-3, Value=test1
Item2: Key=2, Value=test2
Item4: Key=4, Value=test3
Item5: Key=5, Value=test4
I managed to get the duplicates using this: myDictionary.GroupBy(x => x.Value).Where(x => x.Count() > 1);
But I can't figure the right way to build a new Dictionary from this.

This works for taking all the duplicate items into a new dictionary with a shared key:
var dict = new Dictionary<string, string>
{
{"1", "test1"},
{"2", "test2"},
{"3", "test1"}
};
var groupedKeyMap = dict.GroupBy(x => x.Value)
.Where(x => x.Count() > 1)
.ToDictionary(x => string.Join("-", x.Select(y => y.Key)),
x => x.Key);
If you need both duplicate and non duplicate key value pairs, remove the Where clause:
var groupedKeyMap = dict.GroupBy(x => x.Value)
.ToDictionary(x => string.Join("-", x.Select(y => y.Key)),
x => x.Key);

Related

How to combine duplicate values in dictionary into one value

I have dictionary with duplicate values. How to join this duplicate values into one value
Example:
Accord - first
Accord.s - first
I want to see something like:
Accord, Accord.s - first
If I've understood you right, you have a dictionary
Dictionary<string, string> source = new Dictionary<string, string>() {
{"Accord", "first"},
{"Accord.s", "first"},
{"Gamma", "second"},
};
and you want to group by Value, which you can do with a help of Linq:
using System.Linq;
...
// If you want to create a dictionary:
Dictionary<string, string> result = source
.GroupBy(pair => pair.Value)
.ToDictionary(
chunk => string.Join(", ", chunk.Select(pair => pair.Key)),
chunk => chunk.Key);
string report = string.Join(Environment.NewLine, result
.Select(pair => $"{pair.Key} : {pair.Value}"));
Console.Write(report);
Outcome:
Accord, Accord.s : first
Gamma : second
In case you want just a query (not dictionary)
var result = source
.GroupBy(pair => pair.Value)
.Select(chunk => new {
Key = string.Join(", ", chunk.Select(pair => pair.Key)),
Value = chunk.Key});
// and then
string report = string.Join(Environment.NewLine, result
.Select(pair => $"{pair.Key} : {pair.Value}"));

How can I retrieve duplicate key value pairs?

public static IEnumerable<KeyValuePair<string, string>> GetGroupKeyValuePairs(string category)
{
var list = new List<KeyValuePair<string, string>>();
using (DataConnection connection = new DataConnection())
{
List<KeyValuePair<string,string>> settings = connection.Get<Settings>()
.Where(a => a.Category == category )
.Select(pair => new KeyValuePair<string,string>(pair.TheName, pair.TheValue))
.ToList();
list = settings;
}
return list;
}
The exception is:
InvalidOperationException:
Key 'Garanti.Oda' appears more than one time
How can I collect duplicate keys?
The method that you show isn't going to have a problem with multiple pairs with the same key. I assume that afterward, you're doing something like creating a dictionary of these pairs, and that's where you have a problem. E.g.
var pairs = GetGroupKeyValuePairs("some category");
var dict = new Dictionary<string, string>();
foreach (var pair in pairs)
dict.Add(pair.Key, pair.Value); // exception when it hits a duplicate
Instead, you need to use the pairs in a way that's friendly to duplicates, e.g. ToLookup.
var pairs = GetGroupKeyValuePairs("some category");
var lookup = pairs.ToLookup(x => x.Key, x => x.Value);
Then, for example if the list had "a", "b" and "a", "c", then lookup["a"] gives you "b" and "c".
Assuming you want to find duplicates by Key only (e.g. so that you can build a dictionary), you could GroupBy the prospective key and find all instances of more than one:
var dupeSettings = connection.Get<Settings>()
.Where(a => a.Category == category)
.GroupBy(a => a.TheName)
.Where(grp => grp.Count() > 1)
.Select(dupe => dupe.Key)
.ToList();
Or, if you want duplicates of both key and value, project and group by an anonymous class:
var dupeSettings = connection.Get<Settings>()
.Where(a => a.Category == category)
.GroupBy(a => new {a.TheName, a.TheValue})
.Where(grp => grp.Count() > 1)
.Select(dupe => dupe.Key) // Key.TheName, Key.TheValue
.ToList();

Linq to Entities group query giving list of results in each group

If I have a set of entities with 3 properties (Id, Type, Size) all of which are strings.
Is there a way using Linq to Entities where I can do a group query which gives me the Size + Type as the key and then a list of the related Id's for that Size + Type?
Example below of getting the count:
Items.GroupBy(x => new { x.Size, x.Type})
.Select(x => new { Key = x.Key, Count = x.Count() })
but I am looking to get a list of the Ids for each grouping?
I am looking to see if it is possible using Linq-to-EF before I decide to iterate through this in code and build up the result instead.
If you want to get List of Ids for each group then you have to select x.Select(r => r.Id) like:
var result = Items.GroupBy(x => new { x.Size, x.Type })
.Select(x => new
{
Key = x.Key,
Ids = x.Select(r => r.Id)
});
Another way to build up a Dictionary<string, IEnumerable<string?>> in dotnet 6.0 according to the docs;
where we have the dictionary Key as {Size, Type} and Value the list of Ids, you can write:
Dictionary<string, IEnumerable<string?>> result = Items.GroupBy(item => new { item.Size, item.Type }
item => item.Id),
(itemKey, itemIds) =>
{
Key = itemKey,
Ids = itemIds
})
.ToDictionary(x => x.Key, x=> x.Ids);

Dictionaries: An item with the same key has already been added

In my MVC app I am using 2 dictionaries to populate SelectList for DropDownList. Those dictionaries will be supplied with dates as string and datetime values.
I have this chunk of code for the first dictionary that works just fine:
if (m_DictDateOrder.Count == 0)
{
m_DictDateOrder = new Dictionary<string, DateTime>();
m_DictDateOrder =
m_OrderManager.ListOrders()
.OrderBy(x => x.m_OrderDate)
.Distinct()
.ToDictionary(x => x.m_OrderDate.ToString(), x => x.m_OrderDate);
}
But when I get to the second dictionary:
if (m_DictDateShipped.Count == 0)
{
m_DictDateShipped = new Dictionary<string, DateTime>();
m_DictDateShipped =
m_OrderManager.ListOrders()
.OrderBy(x => x.m_ShippedDate)
.Distinct()
.ToDictionary(x => x.m_ShippedDate.ToString(), x => x.m_ShippedDate);
}
I get a runtime error on the LINQ request for the second dictionary:
An item with the same key has already been added.
I first though that I add to instantiate a new dictionary (that's the reason for the "new" presence), but nope. What did I do wrong?
Thanks a lot!
You are Distinct'ing the rows, not the dates.
Do this instead:
if (m_DictDateShipped.Count == 0)
{
m_DictDateShipped = m_OrderManager.ListOrders()
//make the subject of the query into the thing we want Distinct'd.
.Select(x => x.m_ShippedDate)
.Distinct()
.ToDictionary(d => d.ToString(), d => d);
}
Don't bother sorting. Dictionary is unordered.
My standard pattern for this (since I have disdain for Distinct) is:
dictionary = source
.GroupBy(row => row.KeyProperty)
.ToDictionary(g => g.Key, g => g.First()); //choose an element of the group as the value.
You applied the Distinct to the order, not to the date. Try
m_OrderManager.ListOrders()
.OrderBy(x => x.m_ShippedDate)
.Select(x =>x.m_ShippedDate)
.Distinct()
.ToDictionary(x => x.ToString(), x => x);

Get Unique values from List<Dictionary<string, string>>

I have List<Dictionary<string, string>> object with some datas in it.
/* Values in the list will be like
[0] -
aaa - aaaValue1 (Key, Value)
bbb - bbbValue1
ccc - cccValue1
ddd - dddValue1
[1] -
aaa - aaaValue2 (Key, Value)
bbb - bbbValue2
ccc - cccValue2
ddd - dddValue2
and so on */
I want to get the distinct values( List<string> ) in the dictionary where the key is equal to "ccc" and the value of the key "bbb" is equal to "bbbValue1".
Expected Result:
Return a string list contains the dictionary value where key is equal to "ccc" and the value of the key "bbb" is equal to "bbbValue1" in the List<Dictionary<string, string>>.
I think you want:
var result = testData.Where(dict => dict.ContainsKey("EmpNo"))
.Select(dict => dict["EmpNo"])
.Distinct()
.ToList();
or if you want the result as a set:
var result = new HashSet<string>(from dict in testData
where dict.ContainsKey("EmpNo")
select dict["EmpNo"]);
EDIT:
You've changed your question completely, which isn't a nice thing to do (ask a new one instead), but to answer it in its current state:
var result = testData.Where(dict => dict.ContainsKey("ccc")
&& dict.ContainsKey("bbb")
&& dict["bbb"] == "bbbValue1")
.Select(dict => dict["ccc"])
.Distinct()
.ToList()
Think it will be better to flatten list like this:
testData.SelectMany(x => x)
.Where(x => x.Key == "EmpNo")
.Select(x => x.Value)
.Distinct()
.ToList();
I think this will give you the correct result:
var result = testData.SelectMany(dict => dict)
.Where(dict => dict.Key.Equals("ccc") || (d.Key.Equals("bbb") && d.Value.Equals("bbbValue1")))
.Select(d => d.Value).Distinct().ToList();

Categories

Resources