[英]Get a list of first names with last name initials if necessary
So in my JS I have an object like so; 所以在我的JS中,我有一个像这样的对象;
[
{
firstname: "John",
lastname: "Smith"
},
{
firstname: "Peter",
lastname: "Gregory"
},
{
firstname: "John",
lastname: "Fisher"
},
{
firstname: "Sam",
lastname: "Fisher"
}
]
And I'd like to display the first names in a comma-separated string. 我想用逗号分隔的字符串显示名字。 Now this would be simple enough, but I also want to display the first initial of the last name only where necessary, to distinguish two people with the same first name. 现在这已经足够简单了,但是我也想只在必要时显示姓氏的名字的首字母,以区分两个具有相同名字的人。
So, in the end, I'd have this: 因此,最后,我将得到以下信息:
John S., Peter, John F., Sam
Thus far I've been able to do a loop that remembers past initials, but the problem for me becomes the fourth entry in the example; 到目前为止,我已经能够进行一个循环,以记住过去的首字母缩写,但是对我而言,问题就变成了示例中的第四项。 someone with a last name that has had to be distinguished with someone else, but who doesn't a share a first name with anyone. 姓氏必须与其他人区分开来,但不与任何人共享名字的人。
What would be the smartest way of going about this? 解决这个问题的最明智的方法是什么?
Array.map + Array.join will do it. Array.map + Array.join可以做到。 I included a polyfill for Array.map if you need it at the bottom. 如果您需要在底部添加一个Array.map的polyfill。
var people = [ { firstname: "John", lastname: "Smith" }, { firstname: "Peter", lastname: "Gregory" }, { firstname: "John", lastname: "Fisher" }, { firstname: "Sam", lastname: "Fisher" } ] /* Count number of firstNames */ var firstnames = {}; for (var i = 0; i < people.length; i++) { if (!firstnames[people[i].firstname]) { firstnames[people[i].firstname] = 0; } firstnames[people[i].firstname] ++; } /* Create the string of names */ var peopleString = people.map(function (a) { /* Check if we need a last name here */ var lastname = firstnames[a.firstname] > 1 ? (a.lastname ? ' ' + a.lastname.substr(0, 1) + '.' : '') : ''; return a.firstname + lastname; }).join(', '); document.write(peopleString); /*Polyfill for Array.map taken from MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map#Polyfill*/ // Production steps of ECMA-262, Edition 5, 15.4.4.19 // Reference: http://es5.github.io/#x15.4.4.19 if (!Array.prototype.map) { Array.prototype.map = function(callback, thisArg) { var T, A, k; if (this == null) { throw new TypeError(' this is null or not defined'); } // 1. Let O be the result of calling ToObject passing the |this| // value as the argument. var O = Object(this); // 2. Let lenValue be the result of calling the Get internal // method of O with the argument "length". // 3. Let len be ToUint32(lenValue). var len = O.length >>> 0; // 4. If IsCallable(callback) is false, throw a TypeError exception. // See: http://es5.github.com/#x9.11 if (typeof callback !== 'function') { throw new TypeError(callback + ' is not a function'); } // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. if (arguments.length > 1) { T = thisArg; } // 6. Let A be a new array created as if by the expression new Array(len) // where Array is the standard built-in constructor with that name and // len is the value of len. A = new Array(len); // 7. Let k be 0 k = 0; // 8. Repeat, while k < len while (k < len) { var kValue, mappedValue; // a. Let Pk be ToString(k). // This is implicit for LHS operands of the in operator // b. Let kPresent be the result of calling the HasProperty internal // method of O with argument Pk. // This step can be combined with c // c. If kPresent is true, then if (k in O) { // i. Let kValue be the result of calling the Get internal // method of O with argument Pk. kValue = O[k]; // ii. Let mappedValue be the result of calling the Call internal // method of callback with T as the this value and argument // list containing kValue, k, and O. mappedValue = callback.call(T, kValue, k, O); // iii. Call the DefineOwnProperty internal method of A with arguments // Pk, Property Descriptor // { Value: mappedValue, // Writable: true, // Enumerable: true, // Configurable: true }, // and false. // In browsers that support Object.defineProperty, use the following: // Object.defineProperty(A, k, { // value: mappedValue, // writable: true, // enumerable: true, // configurable: true // }); // For best browser support, use the following: A[k] = mappedValue; } // d. Increase k by 1. k++; } // 9. return A return A; }; }
I guess you could do something like this: 我猜你可以做这样的事情:
var o = {};
var arr = [];
people.forEach(function(val) {
if (!o.hasOwnProperty(val.firstname)) {
// didn't see this name before,
// keeping it so we know we saw it
// and keeping its index, in case we see the same name again
var idx = arr.push(val.firstname);
o[val.firstname] = { idx: idx - 1, val: val };
}
else {
// we saw this name, adding the current with a last name
// also adding last name to the origninal we saved before
arr.push(val.firstname + " " + val.lastname.substr(0, 1));
arr[o[val.firstname].idx] = o[val.firstname].val.firstname + " " + o[val.firstname].val.lastname.substr(0, 1);
}
})
console.log(arr);
Just if you want an (almost) inline solution... 只是如果您想要一个(几乎)内联解决方案...
var arr = [
{
firstname: "John",
lastname: "Smith"
},
{
firstname: "Peter",
lastname: "Gregory"
},
{
firstname: "John",
lastname: "Fisher"
},
{
firstname: "Sam",
lastname: "Fisher"
}
];
var out = arr.map (function(i){
return arr.filter(function(e){
return e.firstname == i.firstname && true;
}, []).length > 1 ? (i.firstname + " " + i.lastname.charAt(0)) : (i.firstname);
}, []).toString();
console.log(out);
fiddle http://jsfiddle.net/owqc35p3/2/ 小提琴http://jsfiddle.net/owqc35p3/2/
It will not be that performant compared to many others though, because we're looping arr every time inside the current arr map (also, .toString()
can be replaced by .join(" ,");
) 不过,与其他许多功能相比,性能并不是那么好,因为我们每次都在当前的arr映射内循环arr(同样, .toString()
可以由.join(" ,");
代替)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.