Search code examples
javascriptecmascript-6lodash

Optimal expression to evaluate condition and set both flag and value


Below are two functions that iterate through a collection of objects to evaluate if any items object's id is equal to the function's id argument. If true then it sets an active flag and sets the current variable to equal the id.

NOTES:

  1. function longerVersion(id) if the verbose / longer approach
  2. function shorterVersion(id) is my current optimal approach

QUESTION

  1. Is there a better approach in ES6 and or lodash to achieve the same result?

const items = {1:{id:1,active:false},2:{id:2,active:false}, 3:{id:3,active:false}}
let current = 0;

function longerVersion(id) {
  for (const k in this.items) {
    if (this.items[k].id === id) {
      this.items[k].active = true
      current = id
    } else {
      this.items[k].active = false
    }
  }
}

function shorterVersion(id) {
  for (const k in this.items) {
    items[k].active = items[k].id === id && ((current = id) && true)
  }
}

longerVersion(2);
console.log(current); // expected outcome : (current === 2)
console.log(items); // expected outcome :  items: {1:{id:1,active:false},2:{id:2,active:true}, 3:{id:3,active:false}}

shorterVersion(3);
console.log(current); // expected outcome : (current === 3)
console.log(items); // expected outcome :  items: {1:{id:1,active:false},2:{id:2,active:false}, 3:{id:3,active:true}}


Solution

  • Updating current inside the scope of the function is a side-effect you want to avoid. Instead let it be the returning value of the function.

    const items = {1:{id:1,active:false},2:{id:2,active:false}, 3:{id:3,active:false}};
    
    const functionalVersion = (items, id) => Object.values(items).reduce((acc, x) => {
      x.active = x.id === id;
      return x.active ? id : acc;
    }, -1);
    
    let current = functionalVersion(items, 2);
    console.log(current); // expected outcome : (current === 2)
    console.log(items); // expected outcome :  items: {1:{id:1,active:false},2:{id:2,active:true}, 3:{id:3,active:false}}
    
    current = functionalVersion(items, 3);
    console.log(current); // expected outcome : (current === 3)
    console.log(items); // expected outcome :  items: {1:{id:1,active:false},2:{id:2,active:false}, 3:{id:3,active:true}}

    The function returns a -1 when none of the items id's match the id.

    I don't like assignments in expressions but if that's your thing you can do it in an one-liner:

    const functionalVersion = (items, id) => Object.values(items).reduce((acc, x) => x.active = x.id === id ? id : acc, -1);