A bunch of key/value pairs, from an object that may have duplicate keys, need to be added to a dictionary. Only the first distinct instance of a key (and the instance’s value) should be added to the dictionary.
Below is an example implementation that appears, at first, to work fine.
void Main()
{
Dictionary<long, DateTime> items = new Dictionary<long, DateTime>();
items = AllItems.Select(item =>
{
long value;
bool parseSuccess = long.TryParse(item.Key, out value);
return new { value = value, parseSuccess, item.Value };
})
.Where(parsed => parsed.parseSuccess && !items.ContainsKey(parsed.value))
.Select(parsed => new { parsed.value, parsed.Value })
.Distinct()
.ToDictionary(e => e.value, e => e.Value);
Console.WriteLine(string.Format("Distinct: {0}{1}Non-distinct: {2}",items.Count, Environment.NewLine, AllItems.Count));
}
public List<KeyValuePair<string, DateTime>> AllItems
{
get
{
List<KeyValuePair<string, DateTime>> toReturn = new List<KeyValuePair<string, DateTime>>();
for (int i = 1000; i < 1100; i++)
{
toReturn.Add(new KeyValuePair<string, DateTime>(i.ToString(), DateTime.Now));
toReturn.Add(new KeyValuePair<string, DateTime>(i.ToString(), DateTime.Now));
}
return toReturn;
}
}
If AllItems is modified to return many more pairs, however, then an ArgumentException occurs: “An item with the same key has already been added.”
void Main()
{
Dictionary<long, DateTime> items = new Dictionary<long, DateTime>();
var AllItems = PartOne.Union(PartTwo);
Console.WriteLine("Total items: " + AllItems.Count());
items = AllItems.Select(item =>
{
long value;
bool parseSuccess = long.TryParse(item.Key, out value);
return new { value = value, parseSuccess, item.Value };
})
.Where(parsed => parsed.parseSuccess && !items.ContainsKey(parsed.value))
.Select(parsed => new { parsed.value, parsed.Value })
.Distinct()
.ToDictionary(e => e.value, e => e.Value);
Console.WriteLine("Distinct: {0}{1}Non-distinct: {2}",items.Count, Environment.NewLine, AllItems.Count());
}
public IEnumerable<KeyValuePair<string, DateTime>> PartOne
{
get
{
for (int i = 10000000; i < 11000000; i++)
{
yield return (new KeyValuePair<string, DateTime>(i.ToString(), DateTime.Now));
}
}
}
public IEnumerable<KeyValuePair<string, DateTime>> PartTwo
{
get
{
for (int i = 10000000; i < 11000000; i++)
{
yield return (new KeyValuePair<string, DateTime>(i.ToString(), DateTime.Now));
}
}
}
What is the best way to accomplish this? Note that the use of long.TryParse needs to be present in the solution, as the real input may not include valid Int64’s.
You can achieve this by using the
Enumerable.GroupBymethod and taking the first value in the group: