diff --git a/lib/array/countByProperty.js b/lib/array/countByProperty.js new file mode 100644 index 0000000..44cf90a --- /dev/null +++ b/lib/array/countByProperty.js @@ -0,0 +1,38 @@ +/** + * @alias yd_array_countByProperty + * @category array + * @param {Array} items - 对象数组。 + * @param {string} property - 要统计的属性名。 + * @returns {object} - 一个包含每个属性值出现次数的对象。如果输入无效,则返回空对象。 + * @author penn + * @example + * const characters = [ + * { name: 'Luke Skywalker', eye_color: 'blue' }, + * { name: 'Darth Vader', eye_color: 'yellow' }, + * { name: 'Anakin Skywalker' } // 没有 eye_color 属性 + * ]; + * console.log(countByProperty(characters, 'eye_color')); + * // 输出: { blue: 1, yellow: 1 } + * @description 统计数组中对象指定属性的出现次数。 + */ +export default (items, property) => { + // 检查 items 类型是否为数组 + if (!Array.isArray(items)) { + console.error('countByProperty: items 必须是一个数组'); + return {}; + } + + // 检查 property 是否为有效的字符串 + if (typeof property !== 'string' || property.trim() === '') { + console.error('countByProperty: property 必须是一个非空字符串'); + return {}; + } + + return items.reduce((acc, item) => { + // 检查对象是否有指定的属性,并且属性值不是 undefined + if (item.hasOwnProperty(property) && item[property] !== undefined && item[property] !== null) { + acc[item[property]] = (acc[item[property]] || 0) + 1; + } + return acc; + }, {}); +}; diff --git a/lib/array/countByProperty.test.js b/lib/array/countByProperty.test.js new file mode 100644 index 0000000..c198d1c --- /dev/null +++ b/lib/array/countByProperty.test.js @@ -0,0 +1,41 @@ +import { it, expect, describe } from 'vitest'; +import yd_array_countByProperty from './countByProperty'; + +const characters = [{ name: 'Luke Skywalker', eye_color: 'blue' }, { name: 'Darth Vader', eye_color: 'yellow' }, { name: 'Anakin Skywalker' }]; + +describe('yd_array_countByProperty', () => { + it('should return correct count of a property', () => { + const result = yd_array_countByProperty(characters, 'eye_color'); + expect(result).toEqual({ blue: 1, yellow: 1 }); + }); + + it('should return an empty object if the array is empty', () => { + const result = yd_array_countByProperty([], 'eye_color'); + expect(result).toEqual({}); + }); + + it('should return an empty object if property is not a valid string', () => { + const result = yd_array_countByProperty(characters, 123); + expect(result).toEqual({}); + }); + + it('should return an empty object if items is not an array', () => { + const result = yd_array_countByProperty('characters', 'eye_color'); + expect(result).toEqual({}); + }); + + it('should return an empty object if all objects does not have the specified property', () => { + const result = yd_array_countByProperty([{ name: 'Luke Skywalker' }, { name: 'Darth Vader' }], 'eye_color'); + expect(result).toEqual({}); + }); + + it('should skip objects where the specified property is undefined', () => { + const modifiedCharacters = [ + { name: 'Luke Skywalker', eye_color: 'blue' }, + { name: 'Darth Vader', eye_color: 'yellow' }, + { name: 'Anakin Skywalker', eye_color: undefined } + ]; + const result = yd_array_countByProperty(modifiedCharacters, 'eye_color'); + expect(result).toEqual({ blue: 1, yellow: 1 }); + }); +});