skip to Main Content

so I have an array of values like this

const foodsList = [
  {
    foodOrigin: "Padang",
    foodCode: "SPI",
    foodName: "Nasi Padang"
  },
  {
    foodOrigin: "Padang",
    foodName: "Gulai",
    originCode: "PDN"
  },
  {
    foodOrigin: "Padang",
    foodName: "Rendang",
    originCode: "PDN"
  },
  {
    foodOrigin: "Palembang",
    foodName: "Pempek",
    originCode: "PLG"
  },
  {
    foodOrigin: "Palembang",
    foodName: "Tekwan",
    originCode: "PLG"
  },
  {
    foodOrigin: "Yogyakarta",
    foodName: "Gudeg",
    originCode: "YKT"
  }
];

and I want to filter the array so the result would be like this instead

const filteredFoodsList = [
  {
    foodOrigin: "Padang",
    originCode: "PDN"
  },
  {
    foodOrigin: "Palembang",
    originCode: "PLG"
  },
  {
    foodOrigin: "Yogyakarta",
    originCode: "YKT"
  }
];

In order to achieve the result, I tried doing it like below but is there a cleaner and better way to do this? ( especially since my actual array’s data consist of more than 500 )

const filteredFoodsList = [];
for (let i = 0; i < foodsList.length; i++) {
  if (i === 0) {
    filteredFoodsList.push({
      originCode: foodsList[i].originCode,
      foodOrigin: foodsList[i].foodOrigin
    });
  }
  let isExist = false;
  for (let j = 0; j < filteredFoodsList.length; j++) {
    if (foodsList[i].originCode === filteredFoodsList[j].originCode) {
      isExist = true;
    }
  }
  if (!isExist) {
    filteredFoodsList.push({
      originCode: foodsList[i].originCode,
      foodOrigin: foodsList[i].foodOrigin
    });
  }
}

5

Answers


  1. As the OP stated there should be some focus on performance, so..

    The Map could be the fastest way to collect unique values.
    (I’ve borrowed Array.from(map, ([originCode, foodOrigin]) => ({ foodOrigin, originCode })) from Nina’s answer, really ellegant).

    But it doesn’t affect the performance since the resulting array should be quite small.

    But she forgot to include a Map::has() check that really improves the performance significantly.

    What’s important how fast the source array is iterated. As always I see there can’t be a faster thing then for(let i = 0; ...)

    const foodsList=[{foodOrigin:"Padang",foodName:"Gulai",originCode:"PDN"},{foodOrigin:"Padang",foodName:"Rendang",originCode:"PDN"},{foodOrigin:"Palembang",foodName:"Pempek",originCode:"PLG"},{foodOrigin:"Palembang",foodName:"Tekwan",originCode:"PLG"},{foodOrigin:"Yogyakarta",foodName:"Gudeg",originCode:"YKT"}];
    
    const map = new Map;
    for (let i = 0; i < foodsList.length; i++) {
        const item = foodsList[i];
        map.has(item.originCode) || map.set(item.originCode, item.foodOrigin);
    }
    
    const result = Array.from(map, ([originCode, foodOrigin]) => ({ foodOrigin, originCode }));
    
    console.log(result);

    And a benchmark:

    enter image description here

    <script benchmark data-count="1">
    
        const chunk = [{ foodOrigin: "Padang", foodName: "Gulai", originCode: "PDN" }, { foodOrigin: "Padang", foodName: "Rendang", originCode: "PDN" }, { foodOrigin: "Palembang", foodName: "Pempek", originCode: "PLG" }, { foodOrigin: "Palembang", foodName: "Tekwan", originCode: "PLG" }, { foodOrigin: "Yogyakarta", foodName: "Gudeg", originCode: "YKT" }];
        var foodsList = [];
        let count = 10000000;
        while (count--) {
            foodsList.push(...chunk);
        }
    
        // @benchmark Nina's solution
        Array.from(
            foodsList.reduce((m, { foodOrigin, originCode }) => m.set(foodOrigin, originCode), new Map),
            ([foodOrigin, originCode]) => ({ foodOrigin, originCode })
        );
    
        // @benchmark Alexander's solution
        const map = new Map;
        for (let i = 0; i < foodsList.length; i++) {
            const item = foodsList[i];
            map.has(item.originCode) || map.set(item.originCode, item.foodOrigin);
        }
    
        Array.from(map, ([originCode, foodOrigin]) => ({ foodOrigin, originCode }));
    
        // @benchmark Nina's improved
    
        Array.from(
            foodsList.reduce((m, { foodOrigin, originCode }) => {
                m.has(foodOrigin) || m.set(foodOrigin, originCode);
                return m;
            }, new Map),
            ([foodOrigin, originCode]) => ({ foodOrigin, originCode })
        );
    
    
    </script>
    <script src="https://cdn.jsdelivr.net/gh/silentmantra/benchmark/loader.js"></script>
    Login or Signup to reply.
  2. You can use an object to store the values

    const foodsList = [{
      foodOrigin: 'Padang',
      foodCode: 'SPI',
      foodName: 'Nasi Padang',
    }, {
      foodOrigin: 'Padang',
      foodName: 'Gulai',
      originCode: 'PDN',
    }, {
      foodOrigin: 'Padang',
      foodName: 'Rendang',
      originCode: 'PDN',
    }, {
      foodOrigin: 'Palembang',
      foodName: 'Pempek',
      originCode: 'PLG',
    }, {
      foodOrigin: 'Palembang',
      foodName: 'Tekwan',
      originCode: 'PLG',
    }, {
      foodOrigin: 'Yogyakarta',
      foodName: 'Gudeg',
      originCode: 'YKT',
    }]
    
    const items = {}
    
    for (const item of foodsList) {
      if (item.originCode && !(item.originCode in items)) {
        items[item.originCode] = item
      }
    }
    
    const result = Object.values(items).map(({ originCode, foodName }) => ({ originCode, foodName }))
    
    console.log(result)
    Login or Signup to reply.
  3. You could take a Map and get a new array from it.

    const
        foodsList = [{ foodOrigin: 'Padang', foodName: 'Gulai', originCode: 'PDN' }, { foodOrigin: 'Padang', foodName: 'Rendang', originCode: 'PDN' }, { foodOrigin: 'Palembang', foodName: 'Pempek', originCode: 'PLG' }, { foodOrigin: 'Palembang', foodName: 'Tekwan', originCode: 'PLG' }, { foodOrigin: 'Yogyakarta', foodName: 'Gudeg', originCode: 'YKT' }],
        result = Array.from(
            foodsList.reduce((m, { foodOrigin, originCode }) => m.set(foodOrigin, originCode), new Map),
            ([foodOrigin, originCode]) => ({ foodOrigin, originCode })
        );
    
    console.log(result);
    .as-console-wrapper { max-height: 100% !important; top: 0; }
    Login or Signup to reply.
  4. Here’s my "old-fashioned" approach without Map usage:

    const foodsList = [ { foodOrigin: "Padang", foodCode: "SPI", foodName: "Nasi Padang" }, { foodOrigin: "Padang", foodName: "Gulai", originCode: "PDN" }, { foodOrigin: "Padang", foodName: "Rendang", originCode: "PDN" }, { foodOrigin: "Palembang", foodName: "Pempek", originCode: "PLG" }, { foodOrigin: "Palembang", foodName: "Tekwan", originCode: "PLG" }, { foodOrigin: "Yogyakarta", foodName: "Gudeg", originCode: "YKT" }];
    
    const filteredFoodsList = foodsList.reduce(
      (acc, curr) =>
        curr.originCode &&
        !acc.some(a => a?.originCode === curr.originCode)
          ? [...acc, curr]
          : acc,
      []
    );
    
    console.log(filteredFoodsList);
    Login or Signup to reply.
  5. + + + explanation in progress + + +

    const foodsList = [{
      foodOrigin: "Padang", foodCode: "SPI", foodName: "Nasi Padang"
      // and not ...
      // // foodOrigin: "Padang", foodName: "Nasi Padang", originCode: "SPI",
    }, {
      foodOrigin: "Padang", foodName: "Gulai", originCode: "PDN",
    }, {
      foodOrigin: "Padang", foodName: "Rendang", originCode: "PDN",
    }, {
      foodOrigin: "Palembang", foodName: "Pempek", originCode: "PLG",
    }, {
      foodOrigin: "Palembang", foodName: "Tekwan", originCode: "PLG",
    }, {
      foodOrigin: "Yogyakarta", foodName: "Gudeg", originCode: "YKT",
    }];
    
    
    const { result } = foodsList
      .reduce(({ lookup, result }, { foodOrigin, originCode = null }) => {
    
        if (originCode !== null && !lookup.has(foodOrigin)) {
    
          lookup.set(foodOrigin, true);
          result.push({
            foodOrigin,
            originCode,
          });
        }
        return { lookup, result };
    
      }, { lookup: new Map, result: [] });
    
    console.log({ result });
    .as-console-wrapper { min-height: 100%!important; top: 0; }
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search