计算多次搜索的出现次数

时间:2021-07-20 17:34:32

标签: javascript

我发现这个:count occurrences of search strings in a list (python) 与我需要的解决方案相似,但在 javascript 中。

我有对象数组:

data_items = [
    {
        "no": "1",
        "category": "design",
        "class": "low",
        "status": "open",
    },
    {
        "no": "2",
        "category": "permit",
        "class": "low",
        "status": "close",
    },
    {
        "no": "3",
        "category": "permit",
        "class": "high",
        "status": "open",
    },
    {
        "no": "4",
        "category": "quality",
        "class": "high",
        "status": "close",
    }

]
    

categoryList = [
    "design",
    "permit",
    "quality",
    "safety",
    "commercial"
]

我期望的是计算每个类别包括空结果的出现次数

countCategories = [
       { "design": 1 },
       { "permit": 2 },
       { "quality": 1 },
       { "safety": 0 },
       { "commercial": 0 }
]

以及如何获得结果的多维版本?比如

 countCategories = [
        {
            open: [
                { "design": 1 },
                { "permit": 1 },
                { "quality": 0 },
                { "safety": 0 },
                { "commercial": 0 }
            ]
        }, {
            close: [
                { "design": 0 },
                { "permit": 1 },
                { "quality": 1 },
                { "safety": 0 },
                { "commercial": 0 }
            ]
        }
    ]

我一直在尝试通过减少和过滤来获得结果,但没有成功

感谢您的帮助。

6 个答案:

答案 0 :(得分:0)

您可以像这样计算所有类别,然后将其转换为您想要的任何格式:

const data_items = [{
    "no": "1",
    "category": "design",
    "class": "low",
    "status": "open",
  },
  {
    "no": "2",
    "category": "permit",
    "class": "low",
    "status": "close",
  },
  {
    "no": "3",
    "category": "permit",
    "class": "high",
    "status": "open",
  },
  {
    "no": "4",
    "category": "quality",
    "class": "high",
    "status": "close",
  }
]

const counting = new Map();
for (const item of data_items) {
  let count = counting.get(item.category) || 0;
  counting.set(item.category, count + 1);
}

// Convert it to the format you wanted (even though it's a weird one)
const countCategories = [];
for (const [key, value] of counting) {
  countCategories.push({
    [key]: value
  });
}

console.log(countCategories);
// [
//   {design: 1},
//   {permit: 2},
//   {quality: 1},
// ]


编辑:在我撰写此答案时,您似乎添加了多维版本的要求。您可以重复使用上述代码并运行两次,但一次过滤 item.status === 'open',另一次过滤 'close'。这将为您提供两个结果数组,您可以将它们组合成一个多维版本。

答案 1 :(得分:0)

reduce 的基本思想。

var obj = {
  data_items: [{
      "no": "1",
      "category": "design",
      "class": "low",
      "status": "open",
    },
    {
      "no": "2",
      "category": "permit",
      "class": "low",
      "status": "close",
    },
    {
      "no": "3",
      "category": "permit",
      "class": "high",
      "status": "open",
    },
    {
      "no": "4",
      "category": "quality",
      "class": "high",
      "status": "close",
    }
  ]
}

const result = obj.data_items.reduce(function(acc, item) {
  acc[item.status][item.category] = (acc[item.status][item.category] || 0) + 1;
  return acc;
}, {
  open: {},
  close: {}
});

console.log(result);

如果你想用零预填充你的对象

var obj = {
  categoryList: [
    "design",
    "permit",
    "quality",
    "safety",
    "commercial"
  ],
  data_items: [{
      "no": "1",
      "category": "design",
      "class": "low",
      "status": "open",
    },
    {
      "no": "2",
      "category": "permit",
      "class": "low",
      "status": "close",
    },
    {
      "no": "3",
      "category": "permit",
      "class": "high",
      "status": "open",
    },
    {
      "no": "4",
      "category": "quality",
      "class": "high",
      "status": "close",
    }
  ]
}


const defaultObj = obj.categoryList.reduce(function (acc, key) {
acc[key] = 0;
return acc;
}, {});


  const result = obj.data_items.reduce(function(acc, item) {
    acc[item.status][item.category] += 1;
    return acc;
  }, {
    open: { ...defaultObj
    },
    close: { ...defaultObj
    }
  });

console.log(result);

答案 2 :(得分:0)

使用 reduce 是可行的方法,因为您可以使用打开/关闭数组开始您的最终对象。我添加了一个副本,以便显示它如何根据条件递增。

let data_items = [{
    "no": "1",
    "category": "design",
    "class": "low",
    "status": "open",
  },
  {
    "no": "2",
    "category": "permit",
    "class": "low",
    "status": "close",
  },
  {
    "no": "3",
    "category": "permit",
    "class": "high",
    "status": "open",
  },
  {
    "no": "4",
    "category": "quality",
    "class": "high",
    "status": "close",
  },
  {
    "no": "5",
    "category": "quality",
    "class": "high",
    "status": "close",
  }

]

let result = data_items.reduce((b, a) => {
  let l = b[a.status].findIndex(e => Object.keys(e)[0] === a.category)
  if (l > -1) b[a.status][l][a.category]++;
  else {
    b.open.push({
      [a.category]: a.status === 'open' ? 1 : 0
    });
    b.close.push({
      [a.category]: a.status === 'close' ? 1 : 0
    });
  }
  return b
}, {
  open: [],
  close: []
})

console.log(result)

答案 3 :(得分:0)

您可以使用通常称为 groupBy 的通用分组函数来避免硬编码状态值(打开和关闭)。首先使用 status 键应用它。

然后,在每个状态中,类别计数是一个直接的 reduce()。

最后一个可能是可选的步骤是将对象结果转换为数组(如 OP 所述)...

const data_items = [
    {
        "no": "1",
        "category": "design",
        "class": "low",
        "status": "open",
    },
    {
        "no": "2",
        "category": "permit",
        "class": "low",
        "status": "close",
    },
    {
        "no": "3",
        "category": "permit",
        "class": "high",
        "status": "open",
    },
    {
        "no": "4",
        "category": "quality",
        "class": "high",
        "status": "close",
    }

]
 
// answer an object where each key is the value of key in the array
// and each value is an array of elements with the given key's values
function groupBy(array, key) {
  return array.reduce((acc, el) => {
    let value = el[key];
    if (!acc[value]) acc[value] = [];
    acc[value].push(el);
    return acc;
  }, {});
}

function reduceToCategories(array) {
  return array.reduce((acc, obj) => {
    const cat = obj['category'];
    if (!acc[cat]) acc[cat] = 0;
    acc[cat]++;
    return acc;
  }, {})
}


let groups = groupBy(data_items, 'status');
let result = {}
for (status in groups) {
  result[status] = reduceToCategories(groups[status])
}

// result in an object, rather than an array as the OP requests.
// If an array is necessary, the straight-forward transformation is...

const countCategories = Object.entries(result).map(([key, value]) => ({ [key] : value }))

console.log(countCategories)

答案 4 :(得分:0)

您可以构建频率图,然后将条目映射到键值对对象列表。

const dataItems = [
  { "no": "1", "category": "design" , "class": "low" , "status": "open"  },
  { "no": "2", "category": "permit" , "class": "low" , "status": "close" },
  { "no": "3", "category": "permit" , "class": "high", "status": "open"  },
  { "no": "4", "category": "quality", "class": "high", "status": "close" }
];

const unique = (arr, fn) => [...new Set(arr.map(item => fn(item)).sort())];

const frequency = (arr, keyFn) =>
  arr.reduce((acc, item) =>
    (key => ({ ...acc, [key]: (acc[key] || 0) + 1 }))
    (keyFn ? keyFn(item) : item), {});

const mapToPairs = (map) => Object.entries(map).map(([ k, v ]) => ({ [k]: v }));

const categoryList = unique(dataItems, ({ category }) => category);

console.log(JSON.stringify(categoryList));

const catFreq = mapToPairs(frequency(dataItems, ({ category }) => category));
  
console.log(JSON.stringify(catFreq));

const freq = dataItems
  .reduce((acc, { status, category }) =>
    ({ ...acc, [status]: [...(acc[status] || []), { category }] }), {});

for (let key in freq) {
  freq[key] = mapToPairs(frequency(freq[key], ({ category }) => category));
}

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

答案 5 :(得分:0)

感谢您的回答, 自从我发布这篇文章以来,我一直在尝试,我带来了:

function map_it(data_items, dim_key) {
        var bucket = {};
        categoryList.forEach(function (cat) {
            bucket[cat] = 0;
        })
        data_items.forEach(function (item) {
            if (Object.keys(bucket).indexOf(item.category) >= 0) bucket[item.category]++;
            else bucket[item.category] = 1;
        })
        return bucket;
    }
    console.log(map_it(data_items));
相关问题