开发者

LINQ, SelectMany with multiple possible outcomes

I have a situation where I have lists of objects that have to be merged. Each object in the list will have a property that explains how it should be treated in the merger. So assume the following..

enum Cascade {
  Full,
  Unique,
  Right,
  Left
}

class Note {
  int Id { get; set; }
  Cascade Cascade { get; set; }
  // lots of other data.
}

var list1 = new List<Note>{
 new Note {
   Id = 1,
   Cascade.Full,
   // data
 },
 new Note {
   Id = 2,
   Cascade.Right,
   // data
 }
};
var开发者_如何学编程 list2 = new List<Note>{
  new Note {
   Id = 1,
   Cascade.Left,
   // data
  }
};
var list3 = new List<Note>{
  new Note {
    Id = 1,
    Cascade.Unique,
    // data similar to list1.Note[0]
  }
}

So then, I'll have a method ...

Composite(this IList<IList<Note>> notes){
  return new List<Note> {
      notes.SelectMany(g => g).Where(g => g.Cascade == Cascade.All).ToList()
      // Here is the problem... 
      .SelectMany(g => g).Where(g => g.Cascade == Cascade.Right)
      .Select( // I want to do a _LastOrDefault_ )
      // continuing for the other cascades. 
  }
}

This is where I get lost. I need to do multiple SelectMany statements, but I don't know how to. But this is the expected behavior.

Cascade.Full

The Note will be in the final collection no matter what.

Cascade.Unique

The Note will be in the final collection one time, ignoring any duplicates.

Cascade.Left

The Note will be in the final collection, First instances superseding subsequent instances. (So then, Notes 1, 2, 3 are identical. Note 1 gets pushed through)

Cascade.Right

The Note will be in the final collection, Last instance superseding duplicates. (So Notes 1, 2, 3 are identical. Note 3 gets pushed trough)


I think you should decompose the problem in smaller parts. For example, you can implement the cascade rules for an individual list in a seperate extension method. Here's my untested take at it:

public static IEnumerable<Note> ApplyCascades(this IEnumerable<Note> notes)
    {
        var uniques = new HashSet<Note>();
        Note rightToYield = null;
        foreach (var n in notes)
        {
            bool leftYielded = false;

            if (n.Cascade == Cascade.All) yield return n;
            if (n.Cascade == Cascade.Left && !leftYielded)
            {
                yield return n;
                leftYielded = true;
            }
            if (n.Cascade == Cascade.Right)
            {
                rightToYield = n;
            }
            if (n.Cascade == Cascade.Unique && !uniques.Contains(n))
            {
                yield return n;
                uniques.Add(n);
            } 
        }

        if (rightToYield != null) yield return rightToYield;
    } 
}

This method would allow to implement the original extension method something like this:

    List<Note> Composite(IList<IList<Note>> notes)
    {
        var result = from list in notes
                     from note in list.ApplyCascades()
                     select note;
        return result.ToList();

    }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜