배열에 특정 품종의 항목이 몇 개 있는지 계산하려면 해당 배열을 필터링하고 결과의 길이를 확인할 수 있습니다.
const letters = ['a','b','b','c','c','c']; const numberOfC = letters.filter(letter => letter === 'c').length; console.log(numberOfC); // 3
이것은 O(n)의 시간 복잡도를 가지며, 이는 이러한 유형의 문제에 대한 이론적 이상입니다. 두 번째 배열을 보유하기 위해 약간의 추가 메모리를 사용하지만, 다양한 항목을 하나만 계산하는 경우 이는 일반적인 접근 방식이며 대부분의 상황에서 충분히 효율적입니다. 그러나 배열에 있는 모든 다양한 항목의 개수를 계산하려는 경우에는 효율적인 접근 방식이 아닙니다.
'c'뿐만 아니라 배열에 있는 모든 문자의 개수도 계산하려면 이 기술을 순진하게 적용하면 다음과 같습니다.
const letters = ['a','b','b','c','c','c']; letters.forEach((letter, _, arr) => { const count = arr.filter(otherLetter => otherLetter === letter).length; console.log(letter, count); });
다음과 같은 출력이 생성됩니다.
a 1 b 2 b 2 c 3 c 3 c 3
개수는 정확하지만 중복이 있으므로 먼저 세트를 사용하여 수정할 수 있습니다.
const letters = ['a','b','b','c','c','c']; const uniqueLetters = new Set(letters); for(const letter of uniqueLetters){ const count = letters.filter(otherLetter => otherLetter === letter).length; console.log(letter, count); };
결과 출력에 중복이 없습니다.
a 1 b 2 c 3
그러나 각 필터는 전체 배열을 반복하고 각 고유 문자에 대해 반복해야 하기 때문에 O(n^2)의 시간 복잡도를 갖습니다.
O(n) 시간 복잡도로 이 계산을 수행하는 것이 가능합니다. 일반적인 원칙은 배열을 한 번만 반복하는 것입니다. 발견된 각 항목에 대해 해당 항목에 대한 개수가 이미 있는지 확인하세요. 그렇다면 1씩 늘리세요. 그렇지 않으면 값이 1로 설정된 해당 항목의 개수를 추가하세요.
Javascript에는 개수를 저장하는 데 적합한 두 가지 메커니즘이 있습니다. 객체나 지도를 사용할 수 있습니다. 이는 배열의 map() 메서드가 아니라 Map 데이터 구조에 대한 참조입니다. 지도를 사용하는 것이 더 효율적이지만 이를 위해 개체를 사용하는 것이 여전히 일반적이므로 두 가지를 모두 사용하여 계산하는 방법을 살펴보겠습니다.
const letters = ['a','b','b','c','c','c']; const counts = new Map(); // Creates an empty Map letters.forEach(letter => { if(counts.has(letter)) {//Determine if the letter already has a count counts.set(letter, counts.get(letter) + 1);//Increment existing count } else counts.set(letter, 1);//Set new count to 1 }); console.log(counts); //Map(3) { 'a' => 1, 'b' => 2, 'c' => 3 }
has()는 값이 이미 맵에 있는지 확인합니다. set()은 새 값을 생성하거나 기존 값을 덮어쓰면서 맵에 값을 저장합니다. get()은 현재 값을 가져옵니다. has(), set() 및 get()은 해시가 내부적으로 사용되기 때문에 O(1) 시간 복잡도입니다.
나중에 특정 문자의 개수를 추출하려면 다음과 같이 할 수 있습니다.
console.log(counts.get('c'));//3
객체를 사용하여 계산하는 속도는 느리지만, 엄청난 양의 항목을 계산하지 않으면 성능 차이가 눈에 띄지 않을 수 있습니다. 또한 객체는 지도보다 더 많은 브라우저 지원을 제공하지만 현 시점에서는 그 차이가 거의 중요하지 않습니다. caniuse.com에 따르면 이 글을 쓰는 시점에서 지도는 96.28%의 브라우저에서 지원됩니다. 개체는 Javascript 언어의 필수적인 부분이며 100% 브라우저 지원을 가져야 하지만 caniuse.com에는 이에 대한 목록이 없습니다. 계산을 위해 객체를 사용하는 방법을 배우는 주된 이유는 이 기술을 사용하는 오래된 코드가 많이 존재하기 때문입니다. 이전 코드에서 배운 일부 사람들은 이 접근 방식을 사용하여 새 코드를 작성하기도 합니다.
const letters = ['a','b','b','c','c','c']; const counts = {};//Create empty object for holding counts letters.forEach(letter => { if(letter in counts) {//Check if the count exists counts[letter]++;//Increment the count } else counts[letter] = 1;//Set new count to 1 }); console.log(counts);//{ a: 1, b: 2, c: 3 }
이 코드는 Map을 사용한 코드와 동일한 구조를 따릅니다. 차이점은 맵과 객체의 구문에 있습니다. "in" 키워드는 객체에 해당 이름의 키가 있는지 테스트하는 데 사용됩니다. 대괄호 구문은 값을 가져오고 설정하는 데 모두 사용됩니다. 개체에서 멤버십 테스트, 설정 및 값 가져오기는 O(1) 시간 복잡도 작업입니다. 개체가 내부적으로 키에 대한 해시를 사용하기 때문입니다.
계산하고 있는 물건이 물건이라면 각별한 주의가 필요합니다. 맵은 객체를 키로 저장할 수 있고 유형을 보존하지만 완전히 동일한 키와 값을 가진 완전히 다른 객체가 있는 경우 동등 비교에 문제가 발생합니다.
const m = new Map(); m.set({name: "John"}, 5); console.log(m.has({name: "John"}));//false
이 코드는 두 개체에 참조 동등성이 없기 때문에 "false"를 출력합니다. 두 객체는 키와 값이 동일하지만 완전히 동일한 객체는 아닙니다.
const m = new Map(); const obj = {name: "John"} m.set(obj, 5); console.log(m.has(obj));//true
이 버전의 코드는 "true"를 출력합니다. 왜냐하면 값 집합이 멤버십을 테스트하는 개체와 정확히 동일하기 때문입니다.
대부분의 경우 지도를 사용하여 개체 수를 세려고 시도한 결과 모든 has()가 false를 반환하기 때문에 모든 개체의 개수는 1이 됩니다.
개체를 세기 위해 개체를 사용하는 것은 관련이 있지만 약간 다른 문제가 있습니다. 객체 키는 자동으로 문자열 (기호인 경우 제외)으로 강제 변환됩니다. 객체를 다른 객체의 키로 사용하려고 하면 해당 유형 강제로 "[객체 객체]"와 동일한 키가 생성됩니다.
const obj = {name: "John"} const count = {}; count[obj] = 5; console.log(count);// { '[object Object]': 5 }
The result of trying to count objects using objects is you will end up with an object that has "[object Object]" as the key, and the value will be the total number of all the things that were counted. There won't be any individual counts, because every item is treated as "[object Object]".
It is not common that you would need to count objects. If the need arises, the solution depends on whether or not the objects have a unique property that is guaranteed to be unique. For example, objects that have an id number could be counted by counting the id number occurrences instead of counting occurrences of the whole object.
const employees = [ {id: 1, name: "John"}, {id: 1, name: "John"}, {id: 2, name: "Mary"}, {id: 2, name: "Mary"}, {id: 2, name: "Mary"}, ] const counts = new Map(); employees.forEach(employee => { if(counts.has(employee.id)) { counts.set(employee.id, counts.get(employee.id) + 1); } else counts.set(employee.id, 1); }); console.log(counts);//Map(2) { 1 => 2, 2 => 3 }
This only gives counts with ids and an extra lookup would be needed to associate the counts with names, but we can fix that with a bit more code:
const countsWithNames = []; for(const count of counts) { const employee = employees.find((employee) => employee.id === count[0]); countsWithNames.push({employee, count: count[1]}); } console.log(countsWithNames);
The resulting output is:
[ { employee: { id: 1, name: 'John' }, count: 2 }, { employee: { id: 2, name: 'Mary' }, count: 3 } ]
If there isn't anything like an id that guarantees uniqueness, the only remaining practical option would be to first convert the object to JSON.
const people = [ {name: "John Doe", age: 25}, {name: "John Doe", age: 25}, {name: "Mary Jane", age: 24}, {name: "Mary Jane", age: 24}, {name: "Mary Jane", age: 24} ] const counts = new Map(); people.forEach(person => { const personString = JSON.stringify(person); if(counts.has(personString)) { counts.set(personString, counts.get(personString) + 1); } else counts.set(personString, 1); }); console.log(counts);
The resulting output is:
Map(2) { '{"name":"John Doe","age":25}' => 2, '{"name":"Mary Jane","age":24}' => 3 }
Note that there are limitations to this approach. For example, objects with circular references cannot be stringified using JSON.stringify().
Both the techniques for counting with Maps and for counting with objects can be used to count anything, as long as you can find a way to iterate through the items. Some types of data can be converted to an array, for example, strings can be split, and keys of objects can be accessed as an array via Object.keys().
There are also some iterables that don't need to be converted into an array. For example, it's possible to iterate through the characters of a string by using an index. The same principle can be used in array-like structures like HTML Collections.
위 내용은 자바스크립트로 숫자 세기의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!