skip to Main Content

Fill a empty value of a key-value pair with the next value of the next key.

myitems = {
 'items1': [{first:true, second:false}, {first:true, second:true}],
 'items2': [], //should be filled with {first:true, second:false}
 'items3': [], //should be filled with {first:true, second:false}
 'items4': [{first:true, second:false}, {first:true, second:true}],
 'items5': [{first:false, second:true}],
 'items6': [], //should be filled with {first:true, second:true}
 'items7': [{first:true, second:true}],
}

I have tried the follow:

Object.entries(myItems).forEach(([key, value], index, values: any) => {
   if (!values[index][1].length && values[index+1] && values[index+1][1].length) {
   myItems[key] = [{...values[index + 1][1][0]}]
 }
})

3

Answers


  1. You should listen to the comments about the order of the keys in the object… But maybe the reduceRight method will help you somehow:

    const myItems = {
      'items1': [{first:false, second:false}, {first:false, second:false}],
      'items2': [], //should be filled with {first:true, second:false}
      'items3': [], //should be filled with {first:true, second:false}
      'items4': [{first:true, second:false}, {first:true, second:true}],
      'items5': [{first:false, second:true}],
      'items6': [], //should be filled with {first:true, second:true}
      'items7': [{first:true, second:true}],
    }
    
    const result = Object.entries(myItems).reduceRight( (accumulator, currentValue) => {
      const [key, value] = currentValue;
      if (!value.length) {
        accumulator.unshift([key, [...accumulator[0][1]]]);
      } else {
        accumulator.unshift([key, [...value]]);
      }
      return accumulator;
    }, [] );
    
    console.log( JSON.stringify( Object.fromEntries(result), null, 2 ) );
    Login or Signup to reply.
  2. Object properties order cannot be guaranteed. You should either use Array or Map. So I would rebuild the entire concept of what you’re trying to achieve.

    Anyways, if you insist – for your specific example, an idea could be to use a temporary next variable that stores the last known next’s Object from the Array of Object.values, and use .reduceRight() or .reverse().forEach():

    const myItems = {
      'items1': [{first:true, second:false}, {first:true, second:true}],
      'items2': [], //should be filled with {first:true, second:false}
      'items3': [], //should be filled with {first:true, second:false}
      'items4': [{first:true, second:false}, {first:true, second:true}],
      'items5': [{first:false, second:true}],
      'items6': [], //should be filled with {first:true, second:true}
      'items7': [{first:true, second:true}],
    };
    
    
    let next;
    Object.values(myItems).reverse().forEach((arr, i) => {
      if (!i || arr.length) return next = arr[0];
      arr[0] = {...next};
    });
    
    console.log(myItems);

    But again this is a really bad idea.

    Login or Signup to reply.
  3. Given the data object as you posted it, the order IS guaranteed.
    Here is a solution in TypeScript

    const myItems: Record<string,{first:boolean, second:boolean}[]> = {
     'items1': [{first:true, second:false}, {first:true, second:true}],
     'items2': [], //should be filled with {first:true, second:false}
     'items3': [], //should be filled with {first:true, second:false}
     'items4': [{first:true, second:false}, {first:true, second:true}],
     'items5': [{first:false, second:true}],
     'items6': [], //should be filled with {first:true, second:true}
     'items7': [{first:true, second:true}],
    }
    
    const arr: (keyof typeof myItems)[] =[];
    for (let k in myItems) arr.push(k);
    arr.reverse();
    console.log(arr);
    let last: {first:boolean, second:boolean} | undefined;
    arr.forEach((k,ki)=>{
        if (myItems[k].length===0){
            if (last) myItems[k].push(last);
        }
        else {
            last = myItems[k][0];
        }
    });
    for (let k in myItems) {
        console.log(k);
        console.log(myItems[k][0]);
    }
    

    Typescript Playground

    The output is

    [LOG]: ["items7", "items6", "items5", "items4", "items3", "items2", "items1"] 
    [LOG]: "items1" 
    [LOG]: {
      "first": true,
      "second": false
    } 
    [LOG]: "items2" 
    [LOG]: {
      "first": true,
      "second": false
    } 
    [LOG]: "items3" 
    [LOG]: {
      "first": true,
      "second": false
    } 
    [LOG]: "items4" 
    [LOG]: {
      "first": true,
      "second": false
    } 
    [LOG]: "items5" 
    [LOG]: {
      "first": false,
      "second": true
    } 
    [LOG]: "items6" 
    [LOG]: {
      "first": true,
      "second": true
    } 
    [LOG]: "items7" 
    [LOG]: {
      "first": true,
      "second": true
    } 
    
    

    Here is the relevant MDN documentation on object property order

    The traversal order, as of modern ECMAScript specification, is well-defined and consistent across implementations. Within each component of the prototype chain, all non-negative integer keys (those that can be array indices) will be traversed first in ascending order by value, then other string keys in ascending chronological order of property creation.

    Note: If myItems final properties are empty arrays then they stay as empty arrays because there is nothing to set them with.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search