1

I have in JavaScript JSON object the following code:

{
apple: 'value',
orange: 'value',
string1Pear: 'value',
string1Banana: 'value',
string2Pear: 'value',
string2Banana: 'value',
pineapple: 'value'
}

I need to group the similar keys for a given object without knowing if there is there is such or what they would look like.

The end result should be something like this:

{
apple: 'value',
orange: 'value',
string: {
   string1: {
      string1Pear: 'value',
      string1Banana: 'value',
   },
   string2: {
      string2Pear: 'value',
      string2Banana: 'value',
   },
}
pineapple: 'value'
}
  • would `string` be a static prefix? – RomanPerekhrest Feb 20 '17 at 11:36
  • May be this will give you idea: http://underscorejs.org/#groupBy – Georgi Naumov Feb 20 '17 at 11:38
  • No it could be anything but it will be aways at the beginning. – Bozhidar Georgiev Feb 20 '17 at 11:38
  • and how this key should be treated `'string1string2Pear'` ? – RomanPerekhrest Feb 20 '17 at 11:39
  • 'string1string2Pear' would never exist – Bozhidar Georgiev Feb 20 '17 at 11:42
  • This is confusing: "without knowing if there is there is such..." – Tim Consolazio Feb 20 '17 at 11:45
  • Maybe http://stackoverflow.com/questions/5444945/how-to-check-if-two-string-are-a-partial-match-in-c will help, though it's related to C#, it talks about Levenshtein edit distance algorithm. Maybe it would help, maybe not. – A. L Feb 20 '17 at 11:51
  • I have as solution for this, with one caveat: would it be possible to add a consistent character of any kind to the variable names, for example, instead of string1Pear, could it be string1_pear? Everything else could remain the same. I actually have a solution for it the other way, but the Big O is awful, adding that one simple character to any var with a "prefix" fixes the whole thing. – Tim Consolazio Feb 20 '17 at 11:58
  • I did consider Levenshtein but it will be very inaccurate for this purpose. I have to guess what would be the length of the string which relays to the coefficient index outputted from Levenshtei method. I need to find if there is matches and to group them. – Bozhidar Georgiev Feb 20 '17 at 11:58
  • @Tim Consolazio: Yes underscore should be fine. – Bozhidar Georgiev Feb 20 '17 at 12:02
  • Then it's a matter of iterating the keys, finding the ones with prefixes (which you just split on the underscore to find), storing those prefixes off to the side, then going through them again and grouping by the prefixes. With that info I think you could probably see the solution easily enough. Without the underscore, you'd have to iterate the keys AND iterate the characters in the keys until you found a number, which for perf isn't nice, but then it would work the same way; store the prefixes, see if the other keys have them as substrings at char 0, and group away. – Tim Consolazio Feb 20 '17 at 12:05

2 Answers2

1

The solution using Object.keys(), String.prototype.match() and Array.prototype.reduce() functions:

var data = { apple: 'value', orange: 'value', string1Pear: 'value', string1Banana: 'value', string2Pear: 'value', string2Banana: 'value', pineapple: 'value'},

    result = Object.keys(data).reduce(function (r, k) {
        var parts = k.match(/(\w+\d+)([A-Z]\w+)/);
        if (!parts) {
            r[k] = data[k];
            return r;
        }
        r[parts[1]] = r[parts[1]] || {};
        r[parts[1]][k] = data[k]
        return r;
    }, {});

console.log(result);
RomanPerekhrest
  • 88,541
  • 4
  • 65
  • 105
  • This is perfect! I was just wondering if I want to nest all groups in dedicated container like: string {string1: {...}, string2: {...}}? – Bozhidar Georgiev Feb 20 '17 at 14:11
0

If your keys are camel-cased, and you want to always group by whatever string is before the first uppercase letter, this would work:

const fruits = {
      apple: 'value',
      orange: 'value',
      string1Pear: 'value',
      string1Banana: 'value',
      string2Pear: 'value',
      string2Banana: 'value',
      pineapple: 'value'
  }

  // Split by uppercase letters and take the first word.
  function getGroup(key) {
      return key.split(/(?=[A-Z])/)[0];
  }

  // Group keys 
  let newObject = {};
  const keys = Object.keys(fruits);
  
  for (var i = 0; i < keys.length; i++) {
      const key = keys[i];
      const group = getGroup(key);
      
      if (group === key) {
        newObject[group] = fruits[key];
      }
      else if (newObject.hasOwnProperty(group)) {
        newObject[group][key] = fruits[key];
      }
      else {
         newObject[group] = {};
         newObject[group][key] = fruits[key];
      }
  }
  
  console.log(newObject);
Juuso
  • 487
  • 5
  • 12