Search code examples
javascriptjqueryknockout.jsknockout-validationknockout-mvc

Remove duplicates or distinction from array of objects by knockout.js


How to remove duplicates objects from an array by using Knockout.js

   var ticketgroups = [
      {TicketGroup: TicketGroup1, SortOrder: 1},
      {TicketGroup: TicketGroup1, SortOrder: 1},
      {TicketGroup: TicketGroup2, SortOrder: 2},
      {TicketGroup: TicketGroup2, SortOrder: 2},
      {TicketGroup: TicketGroup3, SortOrder: 3},
      {TicketGroup: TicketGroup3, SortOrder: 3},
    ];

Output should be

 var filltered = [
          {TicketGroup: TicketGroup1, SortOrder: 1},
          {TicketGroup: TicketGroup2, SortOrder: 2},
          {TicketGroup: TicketGroup3, SortOrder: 3},
        ];

How to bind on my views.

<select id="customticketgroup" data-bind="options: $root.filltered.TicketGroup"/>

Solution

  • If SortOrder is supposed to be a unique value, you can use it to filter out duplicates. The example below uses a Map to ensure there's only one value per sort order.

    function uniquesBy(getKey, xs) {
      return Array.from(
        new Map(
          xs.map(x => [getKey(x), x])
        ).values()
      )
    }
    
    const TicketGroup1 = "Ticket Group 1";
    const TicketGroup2 = "Ticket Group 2";
    const TicketGroup3 = "Ticket Group 3";
    
    const ticketgroups = [
      {TicketGroup: TicketGroup1, SortOrder: 1},
      {TicketGroup: TicketGroup1, SortOrder: 1},
      {TicketGroup: TicketGroup2, SortOrder: 2},
      {TicketGroup: TicketGroup2, SortOrder: 2},
      {TicketGroup: TicketGroup3, SortOrder: 3},
      {TicketGroup: TicketGroup3, SortOrder: 3},
    ];
    
    ko.applyBindings({ 
      filtered: uniquesBy(g => g.SortOrder, ticketgroups)
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
    
    <select data-bind="
      options: filtered,
      optionsText: 'TicketGroup'
    "></select>

    If your ticketgroups array is actually an observableArray, you can use a pureComputed for filtered. If you're only interested in the TicketGroup property after sorting, you could chain a .map(g => g.TicketGroup) to extract the values.

    function uniquesBy(getKey, xs) {
      return Array.from(
        new Map(
          xs.map(x => [getKey(x), x])
        ).values()
      )
    }
    
    const TicketGroup1 = "Ticket Group 1";
    const TicketGroup2 = "Ticket Group 2";
    const TicketGroup3 = "Ticket Group 3";
    
    const ticketgroups = ko.observableArray([
      {TicketGroup: TicketGroup1, SortOrder: 1},
      {TicketGroup: TicketGroup1, SortOrder: 1},
      {TicketGroup: TicketGroup2, SortOrder: 2},
      {TicketGroup: TicketGroup2, SortOrder: 2},
      {TicketGroup: TicketGroup3, SortOrder: 3},
      {TicketGroup: TicketGroup3, SortOrder: 3},
    ]);
    
    ko.applyBindings({ 
      filtered: ko.pureComputed(() => 
        uniquesBy(g => g.SortOrder, ticketgroups())
          .map(g => g.TicketGroup)
      )
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
    
    <select data-bind="
      options: filtered
    "></select>