skip to Main Content
sampleData = [{
  RouteId: "1",
  InDirection: "1",
  AreaCode: ["41108", "41109", "41110", "41111"],
}, {
  RouteId: "1",
  InDirection: "2",
  AreaCode: ["41108", "41109", "411011"],
}, {
  RouteId: "2",
  InDirection: "1",
  AreaCode: ["41112", "41114"],
}, {
  RouteId: "2",
  InDirection: "2",
  AreaCode: ["41112", "41114"],
}, {
  RouteId: "3",
  InDirection: "1",
  AreaCode: ["41112", "41114"],
}, {
  RouteId: "3",
  InDirection: "2",
  AreaCode: ["41112", "41114","41108", "41109", "41110"],
}, {
  RouteId: "4",
  InDirection: "1",
  AreaCode: ["41112", "41114","41108", "41110" , "41120", "41121"],
}, {
  RouteId: "4",
  InDirection: "2",
  AreaCode: ["41112", "41114"],
}]

I want to sort above sampleData based on number of entries in AreaCodes and get top 20 results. But I only want one object every RouteId. Every RouteId can have two types of InDirection = 1 or 2. So in the above result would like to removed

{
  RouteId: "1",
  InDirection: "2",
  AreaCode: ["41108", "41109", "411011"],
}

since it less entires on AreaCode as compared to InDirection= 1

so the final sorted result should be

finalResult = [{
  RouteId: "1",
  InDirection: "1",
  AreaCode: ["41108", "41109", "41110", "41111"],
}, {
  RouteId: "2",
  InDirection: "1",
  AreaCode: ["41112", "41114"],
}, {
  RouteId: "3",
  InDirection: "2",
  AreaCode: ["41112", "41114","41108", "41109", "41110"],
}, {
  RouteId: "4",
  InDirection: "1",
  AreaCode: ["41112", "41114","41108", "41110" , "41120", "41121"],
}]

Here I got so far:

    const filteredItems = sampleData.filter(item => {
const otherItem = transformedData.find(i => i.RouteId === item.RouteId && i.InDirection !== item.InDirection);
if (otherItem) {
    return item.AreaCode.length > otherItem.AreaCode.length;
} else {
    return true;
} 
});

But this missed condition where length of AreaCode is equal and the final result is not sorted.

3

Answers


  1. You want to make use of sort and filter functions for arrays, though there may be other ways of doing thins.

    const sampleData = [{
      RouteId: "1",
      InDirection: "1",
      AreaCode: ["41108", "41109", "41110", "41111"],
    }, {
      RouteId: "1",
      InDirection: "2",
      AreaCode: ["41108", "41109", "411011"],
    }, {
      RouteId: "2",
      InDirection: "1",
      AreaCode: ["41112", "41114"],
    }, {
      RouteId: "2",
      InDirection: "2",
      AreaCode: ["41112", "41114"],
    }, {
      RouteId: "3",
      InDirection: "1",
      AreaCode: ["41112", "41114"],
    }, {
      RouteId: "3",
      InDirection: "2",
      AreaCode: ["41112", "41114", "41108", "41109", "41110"],
    }, {
      RouteId: "4",
      InDirection: "1",
      AreaCode: ["41112", "41114", "41108", "41110", "41120", "41121"],
    }, {
      RouteId: "4",
      InDirection: "2",
      AreaCode: ["41112", "41114"],
    }]
    
    
    const routeIdsFound = []
    const result = sampleData.sort(
      (a, b) => b.AreaCode.length - a.AreaCode.length
    ).filter(item => {
      if (!routeIdsFound.includes(item.RouteId)) {
        routeIdsFound.push(item.RouteId)
        return true
      } else {
        return false
      }
    }).sort((a, b) => parseInt(a.RouteId) - parseInt(b.RouteId))
    
    console.log(result);

    You may also want to use something like Lodash, (if you’re not opposed to using an external library), perhaps uniquBy might be something of interest (or sortedUinqBy ?)

    Login or Signup to reply.
  2. You can do this in steps

    • First, sort with Array#sort in descending order of most AreaCodes
    • Then, use Array#reduce to exclude any element whose RouteId already exists prior to the elements index
    const 
          sampleData = [{ RouteId: "1", InDirection: "1", AreaCode: ["41108", "41109", "41110", "41111"], }, { RouteId: "1", InDirection: "2", AreaCode: ["41108", "41109", "411011"], }, { RouteId: "2", InDirection: "1", AreaCode: ["41112", "41114"], }, { RouteId: "2", InDirection: "2", AreaCode: ["41112", "41114"], }, { RouteId: "3", InDirection: "1", AreaCode: ["41112", "41114"], }, { RouteId: "3", InDirection: "2", AreaCode: ["41112", "41114","41108", "41109", "41110"], }, { RouteId: "4", InDirection: "1", AreaCode: ["41112", "41114","41108", "41110" , "41120", "41121"], }, { RouteId: "4", InDirection: "2", AreaCode: ["41112", "41114"], }],
          
          sortFiltered = sampleData.sort((a,b) => b.AreaCode.length - a.AreaCode.length).reduce(
              (filtered,cur) => filtered.find(a => a.RouteId === cur.RouteId) ? filtered : [...filtered,cur], []
          );
          
          
    console.log( sortFiltered );
    Login or Signup to reply.
  3. I personally don’t think filter() is the best solution here.

    If you know that the provided structure always provides exactly two items with the same RouteId after each other. Then you can chunk the array in chunks of size 2. Then map() each chunk by comparing the two elements based on AreaCode.length.

    const desired = chunkN(2, sampleData).map(([inDirection1, inDirection2]) => (
      inDirection1.AreaCode.length >= inDirection2.AreaCode.length
      ? inDirection1
      : inDirection2
    ));
    

    The code above uses a chunkN() helper that I’ve defined in the snippet below. It essentially cuts up the array in chunks of size N. Then we use the conditional (ternary) operator to select if inDirection1 or inDirection2 is the item with the largest AreaCode.length.


    If the provided elements are not strictly structured and can be in any order and there are possibly more then two inDirection options. I would suggest first grouping all the elements based on RouteId. Then sort() each group based on AreaCode.length in a descending manner and select the first item.

    const groups = groupBy(item => item.RouteId, sampleData);
    const desired = Array.from(groups.values(), (group) => (
      // ascending = a - b, descending = b - a
      group.sort((a, b) => b.AreaCode.length - a.AreaCode.length)[0]
    ));
    

    The groupBy() helper is a helper that returns a Map instance. In the example above RouteId is used as the key. The value is an array of items that match this key.

    function solutionA(sampleData) {
      const desired = chunkN(2, sampleData).map(([inDirection1, inDirection2]) => (
        inDirection1.AreaCode.length >= inDirection2.AreaCode.length
        ? inDirection1
        : inDirection2
      ));
      console.log("solutionA", desired);
    }
    
    function solutionB(sampleData) {
      const groups = groupBy(item => item.RouteId, sampleData);
      const desired = Array.from(groups.values(), (items) => (
        // ascending = a - b, descending = b - a
        items.sort((a, b) => b.AreaCode.length - a.AreaCode.length)[0]
      ));
      console.log("solutionB", desired);
    }
    
    // helpers
    function chunkN(n, array) {
      const chunks = [];
      for (let index = 0; index < array.length; index += n) {
        chunks.push(array.slice(index, index + n));
      }
      return chunks;
    }
    
    function groupBy(fnKey, iterable) {
      const groups = new Map();
      for (const item of iterable) {
        const key = fnKey(item);
        if (!groups.has(key)) groups.set(key, []);
        groups.get(key).push(item);
      }
      return groups;
    }
    
    // data + run solutions
    const data = [{
      RouteId: "1",
      InDirection: "1",
      AreaCode: ["41108", "41109", "41110", "41111"],
    }, {
      RouteId: "1",
      InDirection: "2",
      AreaCode: ["41108", "41109", "411011"],
    }, {
      RouteId: "2",
      InDirection: "1",
      AreaCode: ["41112", "41114"],
    }, {
      RouteId: "2",
      InDirection: "2",
      AreaCode: ["41112", "41114"],
    }, {
      RouteId: "3",
      InDirection: "1",
      AreaCode: ["41112", "41114"],
    }, {
      RouteId: "3",
      InDirection: "2",
      AreaCode: ["41112", "41114","41108", "41109", "41110"],
    }, {
      RouteId: "4",
      InDirection: "1",
      AreaCode: ["41112", "41114","41108", "41110" , "41120", "41121"],
    }, {
      RouteId: "4",
      InDirection: "2",
      AreaCode: ["41112", "41114"],
    }];
    solutionA(data);
    solutionB(data);

    Both chunkN() and groupBy() are generic helpers that can be used in lots of other scenarios. You can also achieve the same without helpers (like shown in the two codeblocks below). But defining these helpers separates the thing you want to do (finding the item with the most AreaCodes per RouteId) from the general purpose logic, like grouping or chunking.

    const desired = [];
    for (let index = 0; index < sampleData.length; index += 2) {
      const inDirection1 = sampleData[index];
      const inDirection2 = sampleData[index + 1];
      desired.push(
        inDirection1.AreaCode.length >= inDirection2.AreaCode.length
        ? inDirection1
        : inDirection2
      );
    }
    
    const groups = new Map();
    for (const item of sampleData) {
      if (!groups.has(item.RouteId)) groups.set(item.RouteId, []);
      groups.get(item.RouteId).push(item);
    }
    
    const desired = Array.from(groups.values(), (group) => (
      // ascending = a - b, descending = b - a
      group.sort((a, b) => b.AreaCode.length - a.AreaCode.length)[0]
    ));
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search