Wojciech Szabowicz
Wojciech Szabowicz

Reputation: 4198

c# linqu and to dictionary, can i check if key exists in the proces?

I have a simple question, I am converting sql result using liqu to dictionary it looks like this:

            result.ExtendedRelationshipSet = reader.Read().AsParallel()
                                                          .Select(r =>
                   new RelationshipsSyncComp.RelationshipCollection.ExtendedRelationship()
            {
                Id = r.RelationshipId,
                FromItemId = r.fromDocumentId,
                FromItem = new Item() {Id = r.fromDocumentId},
                FromBridgeId = r.fromBridgeId ?? r.fromDocumentId,
                FromDocumentKey = r.fromDocumentKey,
            }).ToDictionary(x => RelationshipsSyncComp.RelationshipCollection
                                                      .RelationshipResultKey(type, x), x => x);

Key for the dictionary is build from combining from id and to id, but I noticed there not unique (some transaction bug that sometimes duplicates record in db), so basically there are duplicated entry's.

Can I check using above procedure if key in the dictionary already exists, or ignore duplicate keys?

Upvotes: 0

Views: 925

Answers (3)

Valentin
Valentin

Reputation: 5488

You could use Lookup to allow duplicate keys. And use ToLookup method instead of ToDictionary()

If you want to ignore duplicates, you can use DistinctBy before ToDictionary from morelinq or create your own extension

public static IEnumerable<TSource> DistinctBy<TSource, TKey>
     (this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
    HashSet<TKey> keys = new HashSet<TKey>();
    foreach (TSource item in source)
        if (keys.Add(keySelector(element)))
            yield return item ;
 }

And then call it before ToDictionary

     result.ExtendedRelationshipSet = reader.Read().AsParallel()
                                                      .Select(r =>
               new RelationshipsSyncComp.RelationshipCollection.ExtendedRelationship()
        {
            Id = r.RelationshipId,
            FromItemId = r.fromDocumentId,
            FromItem = new Item() {Id = r.fromDocumentId},
            FromBridgeId = r.fromBridgeId ?? r.fromDocumentId,
            FromDocumentKey = r.fromDocumentKey,
        })
       .DistinctBy(x=> RelationshipsSyncComp.RelationshipCollection.RelationshipResultKey(type, x)) 
       .ToDictionary(x => RelationshipsSyncComp.RelationshipCollection.RelationshipResultKey(type, x), x => x);

Upvotes: 2

CooncilWorker
CooncilWorker

Reputation: 415

If you use a .GroupBy() before .ToDictionary() then you can create a dictionary with lists as values.

Upvotes: 0

Hari Prasad
Hari Prasad

Reputation: 16956

Option 1 - Take first item in case of duplicate keys.

      result.ExtendedRelationshipSet = reader.Read().AsParallel().Select(r => new RelationshipsSyncComp.RelationshipCollection.ExtendedRelationship()
        {
            Id = r.RelationshipId,
            FromItemId = r.fromDocumentId,
            FromItem = new Item() {Id = r.fromDocumentId},
            FromBridgeId = r.fromBridgeId ?? r.fromDocumentId,
            FromDocumentKey = r.fromDocumentKey,
        }).GroupBy(g=>RelationshipsSyncComp.RelationshipCollection.RelationshipResultKey(type, x))
          .ToDictionary(x => x.Key, x => x.First());

Option 2 - Filter or ignore items having duplicated Key.

      result.ExtendedRelationshipSet = reader.Read().AsParallel().Select(r => new RelationshipsSyncComp.RelationshipCollection.ExtendedRelationship()
        {
            Id = r.RelationshipId,
            FromItemId = r.fromDocumentId,
            FromItem = new Item() {Id = r.fromDocumentId},
            FromBridgeId = r.fromBridgeId ?? r.fromDocumentId,
            FromDocumentKey = r.fromDocumentKey,
        }).GroupBy(g=>RelationshipsSyncComp.RelationshipCollection.RelationshipResultKey(type, x))
          .Where(e=>e.Count() > 1)  // ignore duplicates
          .ToDictionary(x => x.Key, x => x.First());

Upvotes: 1

Related Questions