0

var geartable = {
  shittyboots: {
    name: "Shitty Boots",
    cost: "500"
  },
  shittyarmor: {
    name: "Shitty Armor",
    cost: "1000"
  },
  shittyhelmet: {
    name: "Shitty Helmet",
    cost: "750"
  }
};

var shops = {
  positions: [
    [2, 3],
    [0, 1],
    [2, 4]
  ],
  inventory: [
    [geartable.shittyboots.name, geartable.shittyboots.cost, "Available"],
    [geartable.shittyarmor.name, geartable.shittyarmor.cost, "Available"],
    [geartable.shittyhelmet.name, geartable.shittyhelmet.cost, "Available"]
  ]
};

function pickRandomItem(gearlist) {
  var result;
  var count = 0;
  for (var item in gearlist) {
    if (Math.random() < 1 / ++count) {
      result = item;
    }
  }
  console.log(geartable.result.cost);
  return result;
}

Hi there. So, my problem, put simply, is that I'm trying to access an index/a property of a parent object property, but when I run the random selector function (pickRandomItem) on geartable and try to access a property of the result, it tells me that geartable.result.cost is undefined. I assume this is because, for some god forsaken reason, JavaScript is trying to find a property 'result' inside of geartable instead of looking for a property with the value of result inside of geartable.

Is there any way around this? I'm at the end of my rope and I can't imagine there is, due to the fact that object nesting is already pretty shifty as-is. I've tried this with arrays in the place of nested objects, but geartable.result[0]... etc still returns undefined.

This is the error in the JavaScript console, if you're curious:

pickRandomItem(geartable);
TypeError: geartable.result is undefined; can't access its "cost" property[Learn More]

1 Answers1

0

One problem is:

for (var item in gearlist) {
  // ...
  result = item;
// ...
console.log(geartable.result.cost);

for..in loops iterate over property names (not values), and result never becomes a property of geartable. If you wanted to put a result property on the object, you would have to explicitly assign it:

for (var item in gearlist) {
  if (Math.random() < 1 / ++count) {
    gearlist.result = gearlist[item];
  }
}

And then you could access gearlist.result in the future. Or, if you don't want to mutate the input object, just assign to the result variable, and to access the result later, access the result variable name later, not the geartable.result property.

Another problem is that the if (Math.random() < 1 / ++count) test is not balanced - objects occurring later will be more likely to be chosen than objects occurring earlier. A balanced random result can be produced by choosing a random item from an array of the object values, by using Math.random() only once:

const values = Object.values(gearlist);
const randomValue = values[Math.floor(Math.random() * values.length)];
console.log(randomValue.cost);
return randomValue;

var geartable = {
  shittyboots: {
    name: "Shitty Boots",
    cost: "500"
  },
  shittyarmor: {
    name: "Shitty Armor",
    cost: "1000"
  },
  shittyhelmet: {
    name: "Shitty Helmet",
    cost: "750"
  }
};

var shops = {
  positions: [
    [2, 3],
    [0, 1],
    [2, 4]
  ],
  inventory: [
    [geartable.shittyboots.name, geartable.shittyboots.cost, "Available"],
    [geartable.shittyarmor.name, geartable.shittyarmor.cost, "Available"],
    [geartable.shittyhelmet.name, geartable.shittyhelmet.cost, "Available"]
  ]
};

function pickRandomItem(gearlist) {
  const values = Object.values(gearlist);
  const randomValue = values[Math.floor(Math.random() * values.length)];
  console.log(randomValue.cost);
  return randomValue;
}
pickRandomItem(geartable);
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • Yep! That seems to be the case. Thanks, man. I was just labeling it wrong. geartable[result].cost, not geartable.result.cost. Apologies for the duplicate question, couldn't find it anywhere. – Jacob Davis Oct 29 '18 at 00:37