How to get default array filter object if it not exist in Javascript

Viewed 2525

I have an array:

const data = [
              {location: "Phnom Penh", sale: 1000 },
              {location: "Kandal", sale: 500 },
              {location: "Takeo", sale: 300 },
              {location: "Kompot", sale: 700 },
              {location: "Prey Veng", sale: 100 },
              {location: "Seam Reap", sale: 800 },
              {location: "Null", sale: 0}
            ];

and this is my function filter:

function getSale(data, arr) {
  return data
    .filter(el => arr.includes(el.location))
}
arr = getSale(data, ['Phnom Penh', 'AA', 'Kompot', 'BB']);
console.log(arr);
result: [{
    location: "Phnom Penh",
    sale: 1000
  },
  {
    location: "Kompot",
    sale: 700
  }
]

If 'AA' not found in filter I want it get the 'Null' Object.

My purpose I want the result like this:

 result: [
  {location: "Phnom Penh", sale: 1000},
  {location: "Null", sale: 0},
  {location: "Kompot", sale: 700},
  {location: "Null", sale: 0}
 ]

How I do? Thanks for help.

8 Answers

You should rather use .map and .find:

const data = [
  { location: 'Phnom Penh', sale: 1000 },
  { location: 'Kandal', sale: 500 },
  { location: 'Takeo', sale: 300 },
  { location: 'Kompot', sale: 700 },
  { location: 'Prey Veng', sale: 100 },
  { location: 'Seam Reap', sale: 800 },
  { location: 'Null', sale: 0 },
];

function getSale(data, arr) {
  return arr.map(el => {
    const found = data.find(obj => obj.location === el);
    return found ? found : { location: 'Null', sale: 0 };
  });
}
arr = getSale(data, ['Phnom Penh', 'AA', 'Kompot', 'BB']);
console.log(arr);

Alternatively create a hash from data array and use .map directly:

const data = [
  { location: 'Phnom Penh', sale: 1000 },
  { location: 'Kandal', sale: 500 },
  { location: 'Takeo', sale: 300 },
  { location: 'Kompot', sale: 700 },
  { location: 'Prey Veng', sale: 100 },
  { location: 'Seam Reap', sale: 800 },
];

const hash = data.reduce((hash, obj) => {
  hash[obj.location] = obj;
  return hash;
}, {});
function getSale(data, arr) {
  return arr.map(el => hash[el] || { location: 'Null', sale: 0 });
}
arr = getSale(data, ['Phnom Penh', 'AA', 'Kompot', 'BB']);
console.log(arr);

You could take a hash table for all locations and return either a known location or the one with Null as location.

const
    getSale = (data, locations) => {
        const sales = data.reduce((r, o) => (r[o.location] = o, r), {});
        return locations.map(l => sales[l] || sales.Null);
    },
    data = [{ location: "Phnom Penh", sale: 1000 }, { location: "Kandal", sale: 500 }, { location: "Takeo", sale: 300 }, { location: "Kompot", sale: 700 }, { location: "Prey Veng", sale: 100 }, { location: "Seam Reap", sale: 800 }, { location: "Null", sale: 0 }],
    locations = ['Phnom Penh', 'AA', 'Kompot', 'BB'],
    result = getSale(data, locations);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Try it here

const B= ['Phnom Penh','AA','Kompot','BB'];
let result = [];
B.forEach(item => result.push(data.find(entry => entry.location === item) || {location: "Null", sale: 0}));
console.log(result);

Result: enter image description here

We can just map of filterArray and if item is not found, then set Null and 0, otherwise we will have existing items:

const uniqueData = new Map(data.map(s=> [s.location, s]));    
const filterArray = ['Phnom Penh', 'AA', 'Kompot', 'BB'];

const result = filterArray.map(f => ({location: (uniqueData.get(f) ? 
    uniqueData.get(f).location : 'Null'),
    sale: uniqueData.get(f) ? uniqueData.get(f).sale : 0}));

An example:

const data = [
   {location: "Phnom Penh", sale: 1000 },
   {location: "Kandal", sale: 500 },
   {location: "Takeo", sale: 300 },
   {location: "Kompot", sale: 700 },
   {location: "Prey Veng", sale: 100 },
   {location: "Seam Reap", sale: 800 },
   {location: "Null", sale: 0}
 ];

 const uniqueData = new Map(data.map(s=> [s.location, s]));

 const filterArray = ['Phnom Penh', 'AA', 'Kompot', 'BB'];

 const result = filterArray.map(f => ({location: 
     (uniqueData.get(f) ? uniqueData.get(f).location : 'Null'),
     sale: uniqueData.get(f) ? uniqueData.get(f).sale : 0}));

 console.log(result);

You can use a map on the array and decide about the appropriate value for each item.

const arr = ['Phnom Penh', 'AA', 'Kompot', 'BB'];
const data = [
    { location: 'Phnom Penh', sale: 1000 },
    { location: 'Kandal', sale: 500 },
    { location: 'Takeo', sale: 300 },
    { location: 'Kompot', sale: 700 },
    { location: 'Prey Veng', sale: 100 },
    { location: 'Seam Reap', sale: 800 },
    { location: 'Null', sale: 0 },
];

const result = arr.map(loc =>
    data.find(obj => obj.location === loc) || { location: 'Null', sale: 0 }
)
console.log(result)

Also here is another solution using a lookup object.

const arr = ['Phnom Penh', 'AA', 'Kompot', 'BB'];
const data = [
    { location: 'Phnom Penh', sale: 1000 },
    { location: 'Kandal', sale: 500 },
    { location: 'Takeo', sale: 300 },
    { location: 'Kompot', sale: 700 },
    { location: 'Prey Veng', sale: 100 },
    { location: 'Seam Reap', sale: 800 },
    { location: 'Null', sale: 0 },
];

const dataLookup = data.reduce((res, obj) => {
    return {...res, [obj.location]: obj}
}, {});
const result = arr.map(loc => dataLookup[loc] || dataLookup.Null);
console.log(result);

You can try something like this:

Idea

  • Get the null object.
  • Loop over location array
  • For each iteration, get the filtered list.
  • If the result has any length, concat it with previous results and return it
  • If the length is 0, concat nullMatch with results and return it

function getSale(data, arr) {
  const result = [];
  const nullMatch = data.find((el) => el.location === 'Null');
  return arr.reduce((acc, loc) => {
    let result = data.filter((el) => el.location === loc);
    return acc.concat(result.length ? result : nullMatch)
  }, [])
}

const data = [
  {location: "Phnom Penh", sale: 1000 },
  {location: "Kandal", sale: 500 },
  {location: "Takeo", sale: 300 },
  {location: "Kompot", sale: 700 },
  {location: "Prey Veng", sale: 100 },
  {location: "Seam Reap", sale: 800 },
  {location: "Null", sale: 0}
];

arr = getSale(data, ['Phnom Penh', 'AA', 'Kompot', 'BB']);

console.log(arr)

You can reduce the array with location values like this:

function getSaleSimplified(data, arr) {
  return arr.reduce( (acc, val) => {
    const found = data.find(v => v.location === val);
    return found ? [...acc, found] : [...acc, {location: `NULL`, sale: 0}];
    }, [] );
}

console.log(getSaleSimplified(getData(), ['Phnom Penh', 'AA', 'Kompot', 'BB']));

function getData() {
  return [{
      location: "Phnom Penh",
      sale: 1000
    },
    {
      location: "Kandal",
      sale: 500
    },
    {
      location: "Takeo",
      sale: 300
    },
    {
      location: "Kompot",
      sale: 700
    },
    {
      location: "Prey Veng",
      sale: 100
    },
    {
      location: "Seam Reap",
      sale: 800
    },
    {
      location: "Null",
      sale: 0
    }
  ];
}
.as-console-wrapper {
  top: 0;
  max-height: 100% !important;
}

What about for loop and filter

const data = [
              {location: "Phnom Penh", sale: 1000 },
              {location: "Kandal", sale: 500 },
              {location: "Takeo", sale: 300 },
              {location: "Kompot", sale: 700 },
              {location: "Prey Veng", sale: 100 },
              {location: "Seam Reap", sale: 800 },
              {location: "Null", sale: 0}
            ];
            
            
function getSale(data, arr) {
  var result = []
  //Iterate over input
  for(var item of arr)
  {
     //Search for data based on input
     var filteredData = data.filter(x => x.location == item)
     //add result based on filtered data
     result.push((filteredData.length > 0) ? filteredData[0] : {location:"Null", sale:0})       
  }
  //Return result
  return result;
}

arr = getSale(data, ['Phnom Penh', 'AA', 'Kompot', 'BB']);
console.log(arr);

Related