过滤复杂的数据结构(数组和对象)

时间:2018-03-04 00:57:04

标签: arrays filter ecmascript-6 javascript-objects

我正在尝试循环并过滤包含不同数组和对象的复杂数据结构,如下所示:

// current tags to filter by
let filterTags = ['Folk', 'Professional']

// return the same data structure that has filtered out any events that dont 
// have SecondaryTag.Title in the filterTags
let filteredEvents = allEvents.filter((el) => {
 return filterTags.includes(el)
});

然而,数据结构由复杂的数组和对象组成,使得这非常复杂。

我尝试过各种各样的东西,这些东西让我把头撞到键盘上。而不是发布我尝试的所有荒谬的事情,我想我会发布我想要在这里完成的事情,希望有些善良的灵魂会帮助我。



let allEvents = [{
    '2018': {
      '03': {
        '31': [
          {
            ID: 1,
            Title: "My Project",
            Date: "2018-02-27",
            SecondaryTag: {
              Title: "Professional"
            }
          }
        ],
        '28': [
          {
            ID: 2,
            Title: "My Project",
            Date: "2018-02-27",
            SecondaryTag: {
              Title: "Business & Professional"
            }
          }
        ]
      },
      '04': {
        '12': [
          {
            ID: 5,
            Title: "My Project2",
            Date: "2018-04-12",
            SecondaryTag: {
              Title: "concert"
            }
          }
        ],
         '2': [
          {
            ID: 7,
            Title: "My Project2",
            Date: "2018-04-12",
            SecondaryTag: {
              Title: "Folk"
            }
          }
        ]
      }
    }
  }];






// This would be the returned filtered structure given the tags
[{
        '2018': {
          '03': {
            '31': [
              {
                ID: 1,
                Title: "My Project",
                Date: "2018-02-27",
                SecondaryTag: {
                  Title: "Professional"
                }
              }
            ],
          },
          '04': {
             '2': [
              {
                ID: 7,
                Title: "My Project2",
                Date: "2018-04-12",
                SecondaryTag: {
                  Title: "Folk"
                }
              }
            ]
          }
        }
      }]




1 个答案:

答案 0 :(得分:0)

这是ES6语法中的函数。

let filtered = {}; //The object or array that will contain the filtered values
filter($toBeFiltered, $filtered, [], 0);  //Run function

function filter(container, obj, keys, level) {
  if (typeof container.SecondaryTag != 'undefined') { //if `SecondaryTag` is an attribute
    let title = container.SecondaryTag.Title; //Get title
    if (filterTags.indexOf(title) > -1) { // If title is what's filtered
      setDeepValue(obj, container, keys, typeof keys[0]); // Set in `filteredEvents` object
    }
    return true; //Stop function
  }

  for (let key in container) {
    let parsed = Array.isArray(container) ? parseInt(key) : key; //Detect Array vs variable
    let copyKeys = [...keys];  //Copy array to prevent key lost
    copyKeys[level] = parsed;
    filter(container[key], obj, copyKeys, level + 1); //Run again
  }
}

function setDeepValue(obj, value, keys, lastType) {  
    let nextType = typeof keys.slice(1, 2)[0]; // Get type of next value
    if (keys.length > 1) { //If not last
    let k = keys.shift(); // Get first value & shift array
    if (obj[k]== null || typeof obj[k] !== 'object'){ // Create object/array if key  doesn't exist
      if (nextType == 'string') {  obj[k] = {}  } // Create array if key is a string
      else if (nextType == 'number') {  obj[k] = [];  } // Create object if key is a number
    }
    setDeepValue(obj[k], value, keys, nextType); // Repeat
  } else { //If value is the last, then set value
    if (lastType == 'string') {  obj[keys[0]] = value;  } // Set value as object if key is a string
    else if (lastType == 'number') {  obj.push(value);  } // Set value as array if key is a number
  }
}

使用OP数据的示例。

let filterTags = ['Folk', 'Business & Professional'];

let allEvents = [{
    '2018': {
      '03': {
        '31': [
          {
            ID: 1,
            Title: "My Project",
            Date: "2018-02-27",
            SecondaryTag: {
              Title: "Business & Professional"
            }
          }
        ],
        '28': [
          {
            ID: 2,
            Title: "My Project",
            Date: "2018-02-27",
            SecondaryTag: {
              Title: "Business & Professional"
            }
          }
        ]
      },
      '04': {
        '12': [
          {
            ID: 5,
            Title: "My Project2",
            Date: "2018-04-12",
            SecondaryTag: {
              Title: "concert"
            }
          }
        ],
         '2': [
          {
            ID: 7,
            Title: "My Project2",
            Date: "2018-04-12",
            SecondaryTag: {
              Title: "Folk"
            }
          }
        ]
      }
    }
  }];
 
let filtered = {};
  
filter(allEvents, filtered, [], 0);
  
function filter(container, obj, keys, level) {
  
  if (typeof container.SecondaryTag != 'undefined') { //if `SecondaryTag` is an attribute
    let title = container.SecondaryTag.Title; //Get title
    if (filterTags.indexOf(title) > -1) { // If title is what's filtered
      setDeepValue(obj, container, keys, typeof keys[0]); // Set in `filteredEvents` object
    }
    return true; //Stop function
  }
  
  for (let key in container) {
    let parsed = Array.isArray(container) ? parseInt(key) : key; //Used later to detect Array vs Object key
    let copyKeys = [...keys];  //Copy array to prevent key lost
    copyKeys[level] = parsed;
    filter(container[key], obj, copyKeys, level + 1); //Run again
  }
}

function setDeepValue(obj, value, keys, lastType) {  
	let nextType = typeof keys.slice(1, 2)[0]; // Get type of next value
	if (keys.length > 1) { //If not last
    let k = keys.shift(); //Shift Array
    if (obj[k ]== null || typeof obj[k] !== 'object') { //If the key doesn't exist or not array/object
      if (nextType == 'string') {  obj[k] = {}  } //Set to empty object is next key is a string
      else if (nextType == 'number') {  obj[k] = [];  } //Set to empty array is next key is a number
    }
    setDeepValue(obj[k], value, keys, nextType); //Repeat
  } else { //If last key
    /* Neccessary? */
    if (lastType == 'string') {  obj[keys[0]] = value;  } //Set object value if last type is object
    else if (lastType == 'number') {  obj.push(value);  } //Set array value if last type is array
  }
}

console.log(filtered);

这个答案利用了Cerbrus的作品。