0

I have an array which contains on the left side of the colon, the name of the level, whilst on the right side, it has the difficulty the level has been completed on.

I want to be able to put this into objects within an array so that later on when I need to check which levels have been completed on the difficulties, I can go to each object in the array to check.

Below is the array I have currently:

   var levels = [
      "Level 1 : Easy", 
      "Level 1 : Normal", 
      "Level 1 : Hard", 
      "Level 2 : Easy", 
      "Level 2 : Normal", 
      "Level 3 : Easy", 
      "Level 3 : Hard"];

How could I put this into objects within an array so it is like this:

var levelCompletion = [
            {
                name: "Level 1",
                easy: true,
                normal: true,
                hard: true
            },
            {
                name: "Level 2",
                easy: true,
                normal: true,
                hard: false
            },
            {
                name: "Level 3",
                easy: true,
                normal: false,
                hard: true
            }
];

Please note that the "levelCompletion" array already exists in my project, however all difficulty values are set to false since I am failing to grasp how I can put the values in the "levels" array into the "levelCompletion" array correctly.

Many thanks

4
  • So, levels is an Array of String and not Array of Object right? Commented Feb 20, 2017 at 14:48
  • @jgr0 yes levels is an array of string Commented Feb 20, 2017 at 14:55
  • Is it always sorted by level? Or should they be treated as unsorted? Commented Feb 20, 2017 at 15:01
  • @Mic they should be treated as unsorted, sorry, should've mentioned that Commented Feb 20, 2017 at 15:03

5 Answers 5

2

You could generate a hash table from the existing levelCompletion and use it for the iteration of levels.

Inside, split the given strings in parts as name and property value, check if a hash does not exists, then generate a new entry with default properties, set to false. Then set the given property to true.

var levels = ["Level 1 : Easy", "Level 1 : Normal", "Level 1 : Hard", "Level 2 : Easy", "Level 2 : Normal", "Level 3 : Easy", "Level 3 : Hard"],
    levelCompletion = [],
    hash = Object.create(null);

levelCompletion.forEach(function (o) {
    hash[o.name] = o;
});

levels.forEach(function (a) {
    var parts = a.split(' : ');
    if (!hash[parts[0]]) {
        hash[parts[0]] = { name: parts[0] };
        ['easy', 'normal', 'hard'].forEach(function (k) { hash[parts[0]][k] = false; });
        levelCompletion.push(hash[parts[0]]);
    }
    hash[parts[0]][parts[1].toLowerCase()] = true;
});

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

Sign up to request clarification or add additional context in comments.

Comments

1

This is how I might approach it, and some of that is just that I lean toward .map and .reduce when I'm transforming an array. map when the output always has exactly the same number of elements as the input, reduce when it has fewer as is the case here. If you're not familiar with it, basically it executes a function on each element, and whatever is returned from that function is supplied as an argument in the next function call (the newLevels argument in my code), with the last one being the return value for the whole thing. The second argument I supplied to the reduce function is an empty array ("[]"), so that when my function gets called on the first element, newLevels is already an initialized array.

Another thing I thought might help is that I made the array index a zero-based counterpart to the level number, so when you want look it up later, levelCompletion[level - 1].easy will get you the completion state where level is the numeric representation of the level (i.e. 1). My temptation would actually be to leave the first element undefined for code readability, which would simply mean removing the "- 1" from the var levelindex line.

var levels = [
      "Level 1 : Easy", 
      "Level 2 : Easy", //Moved this to reflect unsortedness
      "Level 1 : Normal", 
      "Level 1 : Hard", 
      "Level 2 : Normal", 
      "Level 3 : Easy", 
      "Level 3 : Hard"];
      
 var levelCompletion = levels.reduce(function(newLevels,completion){
  var levelsplit = completion.split(':');

  var levelName = levelsplit[0].trim(); // i.e. "Level 1"
  var levelIndex = parseInt(levelName.split(' ')[1]) - 1; // i.e. 0 (for level 1)
  var difficulty = levelsplit[1].trim().toLowerCase(); // i.e. "easy"
  
  if(!newLevels[levelIndex]) {
    newLevels[levelIndex] =  {name:levelName,easy:false,normal:false,hard:false};
  }
  newLevels[levelIndex][difficulty] = true;
  return newLevels;
 },[]);
 
 console.log(levelCompletion);

Comments

1
for (var i=0; i<levels.length; i++){
    var items = levels[i].split(' : ');
    var level = items[0];
    var difficulty = items[1].toLowerCase();
    for (var j=0; j<levelCompletion.length; j++){
        if (levelCompletion[j].name === level) {
            levelCompletion[j][difficulty] = true;
            break;
        }
    }
}

Not being certain of your meaning. You may want to write your levelCompletion like this:

var levelCompletion = {
 "Level 1": {

                easy: true,
                normal: true,
                hard: true
            },
 "Level 2": {
                easy: true,
                normal: true,
                hard: false
            }
}

So you don't need to travel in it in every loop.

Comments

1

var levels = [
  "Level 1 : Easy",
  "Level 1 : Normal",
  "Level 1 : Hard",
  "Level 2 : Easy",
  "Level 2 : Normal",
  "Level 3 : Easy",
  "Level 3 : Hard"
];

var obj = {},t, i, keys = {};
for (i = 0; i < levels.length; i++) 
{
  t = levels[i].split(":");
  t[0] = t[0].trim();
  t[1] = t[1].trim().toLowerCase();
  keys[t[1]] = 1;

  if (t[0] in obj) 
  {
    obj[t[0]][t[1]] = true;
  } else 
  {
    obj[t[0]] = { name: t[0] };
    obj[t[0]][t[1]] = true;
  }
}

var output = Object.keys(obj).map(function(key) {
  for (i in keys) {
    if (!(i in obj[key])) obj[key][i] = false;
  }
  return obj[key]
});

console.log(output);

Comments

0

First, iterate through each level in your array. Then, split it by colon into a list. Place the level name and it's difficulty into a dictionary.

for level in levels:
    sublist=level.split(":")
    levelCompletion[sublist[0]]=[sublist[1]]

The key of the dictionary is the first element in "sublist", and the value is the second element. Sorry, I don't do Javascript I do python, but I hope this gives you a general idea. Also I'm quite a newbie so yeah. And lastly this doesn't make the true and false values only the difficulty level itself, you will have to use a couple of if statements for that. Something like:

if sublist[1]="easy":
    levelCompletion[sublist[0]]="easy: " True

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.