Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. Other Discussions
  3. Clever Code
  4. Collection matching of data/view models with LINQ

Collection matching of data/view models with LINQ

Scheduled Pinned Locked Moved Clever Code
csharpvisual-studiolinqsysadminalgorithms
4 Posts 3 Posters 15 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • I Offline
    I Offline
    Ian Shlasko
    wrote on last edited by
    #1

    I've written code like this before, but found an interesting way to centralize it that I feel the need to share... Basically, I'm linking a collection in my data model to a collection in my view model (M-V-VM). Since the view model is going to be bound to the GUI, I don't want to repopulate it every time there's a change on the back-end... In addition, the data objects will often be replaced instead of modified (Coming down serialized from the server), so I want the view models to just grab the new ones instead of themselves being replaced... So anyway, the objective is to iterate through the view models and data objects side-by-side, and change only that which needs to change on the view side... Normally I'd do this manually, but I decided to see how a heavy-LINQ approach would look...

    PositionTradeModel[] posModels = PositionsInternal.OrderBy(a => a.Data.PositionID).ToArray();
    PositionTrade[] posTrades = newData.Positions.OrderBy(a => a.PositionID).ToArray();

    Util.Algorithms.IterateInParallel(
    posModels, posTrades,
    ((a, b) => a.Data.PositionID.CompareTo(b.PositionID)), // Comparer
    ((a, b) => a.ReplaceData(b)), // Match
    ((a) => PositionsInternal.Remove(a)), // Data removed
    ((a) => PositionsInternal.Add(new PositionTradeModel(a))) // Data added
    );

    (PositionsInternal is an ObservableCollection, so the GUI will catch the updates right away through a ReadOnlyObservableCollection wrapper) A little tricky to read, but that's the nice thing about the XML comments built into Visual Studio... Here's the signature of the actual algorithm:

    /// <summary>
    /// Interate through two sorted lists in parallel, performing a side-by-side match.
    /// </summary>
    /// <typeparam name="TA">Type of list A</typeparam>
    /// <typeparam name="TB">Type of list B</typeparam>
    /// <param name="colA">List A</param>
    /// <param name="colB">List B</param>
    /// <param name="comparer">Comparer function to test equality between a member of each list. Should return 0 for A = B, -1 for A < B, +1 for A > B</param>
    /// <param name="callbackMatch">Called when a match is found, with the two matching objects</param>
    /// <param name="callbackAOnly">Called when an item is found in A that does not match anything in B</param>
    /// <param name="callbackBOnly">Called when an item is found in B that does not match

    R K 2 Replies Last reply
    0
    • I Ian Shlasko

      I've written code like this before, but found an interesting way to centralize it that I feel the need to share... Basically, I'm linking a collection in my data model to a collection in my view model (M-V-VM). Since the view model is going to be bound to the GUI, I don't want to repopulate it every time there's a change on the back-end... In addition, the data objects will often be replaced instead of modified (Coming down serialized from the server), so I want the view models to just grab the new ones instead of themselves being replaced... So anyway, the objective is to iterate through the view models and data objects side-by-side, and change only that which needs to change on the view side... Normally I'd do this manually, but I decided to see how a heavy-LINQ approach would look...

      PositionTradeModel[] posModels = PositionsInternal.OrderBy(a => a.Data.PositionID).ToArray();
      PositionTrade[] posTrades = newData.Positions.OrderBy(a => a.PositionID).ToArray();

      Util.Algorithms.IterateInParallel(
      posModels, posTrades,
      ((a, b) => a.Data.PositionID.CompareTo(b.PositionID)), // Comparer
      ((a, b) => a.ReplaceData(b)), // Match
      ((a) => PositionsInternal.Remove(a)), // Data removed
      ((a) => PositionsInternal.Add(new PositionTradeModel(a))) // Data added
      );

      (PositionsInternal is an ObservableCollection, so the GUI will catch the updates right away through a ReadOnlyObservableCollection wrapper) A little tricky to read, but that's the nice thing about the XML comments built into Visual Studio... Here's the signature of the actual algorithm:

      /// <summary>
      /// Interate through two sorted lists in parallel, performing a side-by-side match.
      /// </summary>
      /// <typeparam name="TA">Type of list A</typeparam>
      /// <typeparam name="TB">Type of list B</typeparam>
      /// <param name="colA">List A</param>
      /// <param name="colB">List B</param>
      /// <param name="comparer">Comparer function to test equality between a member of each list. Should return 0 for A = B, -1 for A < B, +1 for A > B</param>
      /// <param name="callbackMatch">Called when a match is found, with the two matching objects</param>
      /// <param name="callbackAOnly">Called when an item is found in A that does not match anything in B</param>
      /// <param name="callbackBOnly">Called when an item is found in B that does not match

      R Offline
      R Offline
      Robert Rohde
      wrote on last edited by
      #2

      Its too concise and too LINQy... and just right :). I like helper functions like this. But I would change some bits: 1. Why call ToArray on the sorted lists? It should also work without doing so. 2. Instead of passing a comparing function, and two already sorted lists I would pass two delegates transforming TA and TB into something IComparable. This way the function could sort internally and the caller wouldn't have to think about this detail. The function declaration could be something like this:

      public static void IterateInParallel<TA, TB, TID>(IEnumerable<TA> colA, IEnumerable<TB> colB, Func<TA, TID> idFromA, Func<TB, TID> idFromB,
      Action<TA, TB> callbackMatch, Action<TA> callbackAOnly, Action<TB> callbackBOnly)
      where TID : IComparable
      {
      colA = colA.OrderBy(a => idFromA(a));
      colB = colB.OrderBy(b => idFromB(b));

      Func<TA, TB, int> comparer = (a, b) => idFromA(a).CompareTo(idFromB(b));

      //...
      }

      Robert

      I 1 Reply Last reply
      0
      • R Robert Rohde

        Its too concise and too LINQy... and just right :). I like helper functions like this. But I would change some bits: 1. Why call ToArray on the sorted lists? It should also work without doing so. 2. Instead of passing a comparing function, and two already sorted lists I would pass two delegates transforming TA and TB into something IComparable. This way the function could sort internally and the caller wouldn't have to think about this detail. The function declaration could be something like this:

        public static void IterateInParallel<TA, TB, TID>(IEnumerable<TA> colA, IEnumerable<TB> colB, Func<TA, TID> idFromA, Func<TB, TID> idFromB,
        Action<TA, TB> callbackMatch, Action<TA> callbackAOnly, Action<TB> callbackBOnly)
        where TID : IComparable
        {
        colA = colA.OrderBy(a => idFromA(a));
        colB = colB.OrderBy(b => idFromB(b));

        Func<TA, TB, int> comparer = (a, b) => idFromA(a).CompareTo(idFromB(b));

        //...
        }

        Robert

        I Offline
        I Offline
        Ian Shlasko
        wrote on last edited by
        #3

        Robert Rohde wrote:

        1. Why call ToArray on the sorted lists? It should also work without doing so.

        So I can modify the original collections while the function is iterating :)

        Robert Rohde wrote:

        2. Instead of passing a comparing function, and two already sorted lists I would pass two delegates transforming TA and TB into something IComparable. This way the function could sort internally and the caller wouldn't have to think about this detail.

        Thought about that... It would work for this particular situation, as I'm effectively matching them on a single integer value, but remember that these are entirely different types of objects, so while the sorting logic may be simple, the logic to compare an object in one collection to an object in the other could involve more fields. Hmm... Then again, since the matching already depends on the sorting, the functions would really HAVE to correspond, wouldn't they... Will have to give this some more thought.

        Proud to have finally moved to the A-Ark. Which one are you in?
        Author of the Guardians Saga (Sci-Fi/Fantasy novels)

        1 Reply Last reply
        0
        • I Ian Shlasko

          I've written code like this before, but found an interesting way to centralize it that I feel the need to share... Basically, I'm linking a collection in my data model to a collection in my view model (M-V-VM). Since the view model is going to be bound to the GUI, I don't want to repopulate it every time there's a change on the back-end... In addition, the data objects will often be replaced instead of modified (Coming down serialized from the server), so I want the view models to just grab the new ones instead of themselves being replaced... So anyway, the objective is to iterate through the view models and data objects side-by-side, and change only that which needs to change on the view side... Normally I'd do this manually, but I decided to see how a heavy-LINQ approach would look...

          PositionTradeModel[] posModels = PositionsInternal.OrderBy(a => a.Data.PositionID).ToArray();
          PositionTrade[] posTrades = newData.Positions.OrderBy(a => a.PositionID).ToArray();

          Util.Algorithms.IterateInParallel(
          posModels, posTrades,
          ((a, b) => a.Data.PositionID.CompareTo(b.PositionID)), // Comparer
          ((a, b) => a.ReplaceData(b)), // Match
          ((a) => PositionsInternal.Remove(a)), // Data removed
          ((a) => PositionsInternal.Add(new PositionTradeModel(a))) // Data added
          );

          (PositionsInternal is an ObservableCollection, so the GUI will catch the updates right away through a ReadOnlyObservableCollection wrapper) A little tricky to read, but that's the nice thing about the XML comments built into Visual Studio... Here's the signature of the actual algorithm:

          /// <summary>
          /// Interate through two sorted lists in parallel, performing a side-by-side match.
          /// </summary>
          /// <typeparam name="TA">Type of list A</typeparam>
          /// <typeparam name="TB">Type of list B</typeparam>
          /// <param name="colA">List A</param>
          /// <param name="colB">List B</param>
          /// <param name="comparer">Comparer function to test equality between a member of each list. Should return 0 for A = B, -1 for A < B, +1 for A > B</param>
          /// <param name="callbackMatch">Called when a match is found, with the two matching objects</param>
          /// <param name="callbackAOnly">Called when an item is found in A that does not match anything in B</param>
          /// <param name="callbackBOnly">Called when an item is found in B that does not match

          K Offline
          K Offline
          Kevin Drzycimski
          wrote on last edited by
          #4

          Ian Shlasko wrote:

          So what do you think? Too concise? Too LINQy? Or just right

          absolutely right! i also prefer C# coding like this...it makes more like a functional language while keeping the good ol' imperative stuff. my colleagues are slowly going to use these neat feautures :>

          1 Reply Last reply
          0
          Reply
          • Reply as topic
          Log in to reply
          • Oldest to Newest
          • Newest to Oldest
          • Most Votes


          • Login

          • Don't have an account? Register

          • Login or register to search.
          • First post
            Last post
          0
          • Categories
          • Recent
          • Tags
          • Popular
          • World
          • Users
          • Groups