简体   繁体   English

如何根据所包含属性的首字母过滤数组?

[英]How can I filter an array based on the first letter of a contained property?

I have the following JavaScript array of objects: 我有以下对象的JavaScript数组:

[{name: '4 Arn', isLetter: false},
{name: 'Abax', isLetter: false},
{name: 'Aramex', isLetter: false},
{name: 'Booking', isLetter: false},
{name: 'Dangerous', isLetter: false},
{name: 'Manali', isLetter: false}]

In the above array, I want to check the first letter of each item's name property. 在上面的数组中,我想检查每个项目的name属性的首字母。 If it matches, I want to append a new object just before the object, as shown in the following examples: 如果匹配,我想在对象之前追加一个新对象,如以下示例所示:

[{letter: "#", isLetter: true},       // new object 
{name: '4 Arn', isLetter: false},
{letter: "A", isLetter: true},        // new Object
{name: 'Abax', isLetter: false},
{name: 'Aramex', isLetter: false},
{letter: "B", isLetter: true},        // new object
{name: 'Booking', isLetter: false},
{letter: "D", isLetter: true},        // new object
{name: 'Dangerous', isLetter: false},
{letter: "M", isLetter: true},        // new object
{name: 'Manali', isLetter: false}]

I tried the reduce() function, but I don't understand why it's giving me the wrong result: 我尝试了reduce()函数,但是我不明白为什么它给了我错误的结果:

var newArr = [];
list.reduce(function(prev, cur, index, originalArrray) {
    var previousCharcode = prev.name.toUpperCase().charCodeAt(0);
    currentCharCode = cur.name.toUpperCase().charCodeAt(0);

    newArr.push(prev);
    if(previousCharcode != currentCharCode) {
        newArr.splice(index, 0, {isLetter: true, letter: String.fromCharCode(currentCharCode)});
    }
    return cur;
});

There are at least two reasons why your code does not give the expected result: 您的代码没有给出预期结果的原因至少有两个:

  • The index you work with, points to the index in the original array. 您使用的索引指向原始数组中的索引。 As your new array will have more elements, it makes no sense to use that index for a splice on the new array. 由于新数组将包含更多元素,因此在新数组上使用该索引进行splice没有任何意义。 It will be pointing to the wrong place eventually; 最终它将指向错误的位置。

  • You only push the prev element, so the last element will never be pushed to the result array 您只需推送prev元素,所以最后一个元素将永远不会被推送到结果数组

I would suggest to use reduce with a accumulated value (first argument of the callback) that will build up the final array. 我建议使用带有累积值(回调的第一个参数)的reduce来建立最终数组。 To remember the last letter object that was introduced, I will pair this accumulated value with that letter. 为了记住引入的最后一个字母对象,我将把这个累加值与那个字母配对。 So I'll work with an array that contains two elements: 因此,我将使用包含两个元素的数组:

  • The final array being accumulated 最后的数组正在累积
  • The letter of the most recently added letter object 最近添加的字母对象的字母

Then the final result will be taken from the first element of that array, ignoring the second value. 然后,最终结果将从该数组的第一个元素获取,而忽略第二个值。

I suggest not to work with character codes, but just with the characters. 我建议不要使用字符代码,而只能使用字符。 It saves you from converting the code back to a character. 它使您免于将代码转换回字符的麻烦。

Here is the code: 这是代码:

 var list = [ {name: '4 Arn', isLetter: false}, {name: 'Abax', isLetter: false}, {name: 'Aramex', isLetter: false}, {name: 'Booking', isLetter: false}, {name: 'Dangerous', isLetter: false}, {name: 'Manali', isLetter: false} ]; var newArr = list.reduce(function(collect, cur, index, originalArrray) { var currentChar = cur.name.toUpperCase().substr(0,1); if (currentChar < 'A') currentChar = '#'; if (collect[1] != currentChar) { collect[0].push({isLetter: true, letter: currentChar}); collect[1] = currentChar; } collect[0].push(cur); return collect; }, [[], null])[0]; // output console.log(newArr); 

Check this solution. 检查此解决方案。 Iterate the array and append it to a new array. 迭代数组并将其附加到新数组。

 var names = [{ name: '4 Arn', isLetter: false }, { name: 'Abax', isLetter: false }, { name: 'Aramex', isLetter: false }, { name: 'Booking', isLetter: false }, { name: 'Dangerous', isLetter: false }, { name: 'Manali', isLetter: false }]; var newNames = []; for (var i in names) { var char = names[i].name.substring(0, 1); var isNumber = !isNaN(char); var entry = { letter: (isNumber ? '#' : char.toUpperCase()), isLetter: isNumber }; newNames.push(entry); newNames.push(names[i]); } console.log(newNames); 

Maybe with this approach you can resolve the problem 也许用这种方法可以解决问题

 var list = [{name: '4 Arn', isLetter: false}, {name: 'Abax', isLetter: false}, {name: 'Aramex', isLetter: false}, {name: 'Booking', isLetter: false}, {name: 'Dangerous', isLetter: false}, {name: 'Manali', isLetter: false}]; var listResult = []; list.map(function(item, index) { if(index > 0) { var currentCharcode = item.name.toUpperCase().charCodeAt(0); var previousCharcode = list[index-1].name.toUpperCase().charCodeAt(0); if(previousCharcode != currentCharcode) { listResult.push({isLetter: true, letter: String.fromCharCode(currentCharcode)}); } } else { listResult.push({isLetter: true, letter: String.fromCharCode(currentCharcode)}); } listResult.push(item); }); console.log(JSON.stringify(listResult)); 

I guess you can also do in a functional way like this; 我想您也可以通过这样的功能方式进行操作;

 var arr = [{name: '4 Arn', isLetter: false}, {name: 'Abax', isLetter: false}, {name: 'Aramex', isLetter: false}, {name: 'Booking', isLetter: false}, {name: 'Dangerous', isLetter: false}, {name: 'Manali', isLetter: false}], table = arr.reduce((p,c) => {var firstLetter = c.name[0]; isNaN(+firstLetter) ? p[firstLetter] ? p[firstLetter].push(c) : p[firstLetter] = [c] : p["#"] ? p["#"].push(c) : p["#"] = [c]; return p; },{}), result = Object.keys(table).reduce((p,k) => p.concat({letter: k, isLetter: true},table[k]),[]); console.log(result); 

Hints : +"A" returns NaN but +"4" returns 4 as number. 提示:+“ A”返回NaN,但+“ 4”返回4作为数字。 So isNaN() is a very useful function to check the type. 因此, isNaN()是检查类型的非常有用的函数。

Here is the version with conventional functions instead of arrows; 这是具有常规功能而不是箭头的版本;

 var arr = [{name: '4 Arn', isLetter: false}, {name: 'Abax', isLetter: false}, {name: 'Aramex', isLetter: false}, {name: 'Booking', isLetter: false}, {name: 'Dangerous', isLetter: false}, {name: 'Manali', isLetter: false}], table = arr.reduce(function(p,c){ var firstLetter = c.name[0]; isNaN(+firstLetter) ? p[firstLetter] ? p[firstLetter].push(c) : p[firstLetter] = [c] : p["#"] ? p["#"].push(c) : p["#"] = [c]; return p; },{}), result = Object.keys(table).reduce(function(p,k){ return p.concat({letter: k, isLetter: true},table[k]); },[]); console.log(result); 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM