การนับจำนวนการเกิด / ความถี่ขององค์ประกอบอาเรย์


216

ใน Javascript ฉันกำลังพยายามหาค่าตัวเลขเริ่มต้นและนับองค์ประกอบที่อยู่ภายใน ตามหลักการแล้วผลลัพธ์จะเป็นสองอาร์เรย์ใหม่อันแรกที่ระบุองค์ประกอบที่ไม่ซ้ำกันและที่สองมีจำนวนครั้งที่แต่ละองค์ประกอบเกิดขึ้น อย่างไรก็ตามฉันเปิดให้คำแนะนำเกี่ยวกับรูปแบบของการส่งออก

ตัวอย่างเช่นถ้าอาร์เรย์เริ่มต้นคือ:

5, 5, 5, 2, 2, 2, 2, 2, 9, 4

จากนั้นจะสร้างอาร์เรย์ใหม่สองอาร์เรย์ ครั้งแรกจะมีชื่อขององค์ประกอบที่ไม่ซ้ำกันแต่ละ:

5, 2, 9, 4

ที่สองจะมีจำนวนครั้งที่องค์ประกอบที่เกิดขึ้นในอาร์เรย์เริ่มต้น:

3, 5, 1, 1

เนื่องจากหมายเลข 5 เกิดขึ้นสามครั้งในอาเรย์เริ่มต้นหมายเลข 2 จึงเกิดขึ้นห้าครั้งและ 9 และ 4 ทั้งคู่ปรากฏขึ้นหนึ่งครั้ง

ฉันค้นหาวิธีการแก้ปัญหามากมาย แต่ดูเหมือนว่าจะไม่มีอะไรทำงานได้และทุกอย่างที่ฉันลองด้วยตัวเองทำให้ซับซ้อนขึ้นอย่างน่าขัน ความช่วยเหลือใด ๆ ที่จะได้รับการชื่นชม!

ขอบคุณ :)


8
หากสิ่งที่คุณต้องการคือการดูว่าค่าปรากฏขึ้นเพียงครั้งเดียว (แทนที่จะเป็นสองครั้งหรือมากกว่า) คุณสามารถใช้if (arr.indexOf(value) == arr.lastIndexOf(value))
Rodrigo

1
เราสามารถใช้ramda.jsเพื่อให้บรรลุสิ่งนี้ได้อย่างง่ายดาย const ary = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4]; R.countBy(r=> r)(ary)
Eshwar Prasad Yaddanapudi

arr.filter(x => x===5).lengthจะกลับมา3เพื่อระบุว่ามี '3' ห้าในอาร์เรย์
noobninja

คำตอบ:


94

ไปเลย:

function foo(arr) {
    var a = [], b = [], prev;

    arr.sort();
    for ( var i = 0; i < arr.length; i++ ) {
        if ( arr[i] !== prev ) {
            a.push(arr[i]);
            b.push(1);
        } else {
            b[b.length-1]++;
        }
        prev = arr[i];
    }

    return [a, b];
}

การสาธิตสด: http://jsfiddle.net/simevidas/bnACW/

บันทึก

สิ่งนี้จะเปลี่ยนลำดับของอาร์เรย์อินพุตดั้งเดิมที่ใช้ Array.sort


24
มีผลข้างเคียงของการเรียงลำดับอาเรย์ (ผลข้างเคียงไม่ดี), การเรียงลำดับก็คือO(N log(N))และความสง่างามที่ได้รับไม่คุ้มค่าเลย
ninjagecko

1
@ninja คุณชอบคำตอบไหนอีก
Šime Vidas

ในกรณีที่ไม่มีระบบดั้งเดิมระดับสูงที่ดีจากห้องสมุดของบุคคลที่สามฉันมักจะใช้สิ่งนี้เช่นreduceคำตอบ ฉันกำลังจะส่งคำตอบก่อนที่ฉันจะเห็นมันมีอยู่แล้ว อย่างไรก็ตามcounts[num] = counts[num] ? counts[num]+1 : 1คำตอบก็ใช้งานได้ (เทียบเท่ากับif(!result[a[i]])result[a[i]]=0คำตอบที่ดูดีกว่า แต่อ่านง่ายกว่า) คำตอบนี้สามารถแก้ไขได้โดยใช้รุ่น "nicer" ของ for loop บางทีบุคคลที่สามสำหรับ-loop แต่ฉันไม่สนใจเลยว่าเนื่องจากมาตรฐานดัชนีแบบ for-loops นั้นเป็นค่าเริ่มต้นที่น่าเศร้า
ninjagecko

2
@ninja ฉันเห็นด้วย คำตอบเหล่านั้นดีกว่า น่าเสียดายที่ฉันไม่สามารถยกเลิกคำตอบของฉันเองได้
Šime Vidas

สำหรับอาร์เรย์ขนาดเล็กที่เรียงลำดับแบบเรียงซ้อนอาจเร็วกว่าการสร้างอาร์เรย์แบบเชื่อมโยง
quant_dev

219

คุณสามารถใช้วัตถุเพื่อเก็บผลลัพธ์:

var arr = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
var counts = {};

for (var i = 0; i < arr.length; i++) {
  var num = arr[i];
  counts[num] = counts[num] ? counts[num] + 1 : 1;
}

console.log(counts[5], counts[2], counts[9], counts[4]);

ดังนั้นตอนนี้ออบเจ็กต์การนับของคุณสามารถบอกคุณได้ว่าการนับเป็นจำนวนใด:

console.log(counts[5]); // logs '3'

หากคุณต้องการรับอาเรย์ของสมาชิกเพียงใช้keys()ฟังก์ชั่น

keys(counts); // returns ["5", "2", "9", "4"]

3
ควรชี้ให้เห็นว่าObject.keys()ฟังก์ชั่นนี้รองรับเฉพาะ IE9 +, FF4 +, SF5 +, CH6 + แต่ Opera ไม่รองรับ ผมคิดว่าปิดการแสดงที่ยิ่งใหญ่ที่สุดที่นี่คือIE9 +
Robert Koritnik

19
counts[num] = (counts[num] || 0) + 1ในทำนองเดียวกันก็ยังชอบ ด้วยวิธีนี้คุณจะต้องเขียนcounts[num]สองครั้งแทนที่จะเป็นสามครั้งในหนึ่งบรรทัดนั้น
robru

1
นี่เป็นคำตอบที่ดี สิ่งนี้จะถูกทำให้เป็นนามธรรมอย่างง่ายดายในฟังก์ชั่นที่ยอมรับอาร์เรย์และส่งกลับวัตถุ 'จำนวน'
bitsand

นี่เป็นความจริงสำหรับตัวอย่างที่เฉพาะเจาะจงในคำถาม แต่เพื่อประโยชน์ของชาว Google นั้นมีค่าชี้ให้เห็นว่านี่ไม่ใช่เทคนิคที่ปลอดภัยสำหรับการใช้งานที่กว้างขึ้น การจัดเก็บค่าเป็นคีย์วัตถุเพื่อนับจำนวนหมายความว่าคุณกำลังส่งค่าเหล่านั้นไปยังสตริงแล้วนับค่านั้น [5, "5"]เพียงแค่จะบอกว่าคุณมี"5"สองครั้ง [object Object]หรือนับกรณีวัตถุที่แตกต่างบางอย่างเป็นเพียงจะบอกคุณมีจำนวนมากของ ฯลฯ ฯลฯ
Jimbo Jonny

ฉันจะกรองวัตถุที่คืนมาเพื่อแสดงจำนวนสูงสุดถึงต่ำสุดหรือต่ำสุดถึงสูงสุดได้อย่างไร
Ryan Holton

92
var a = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4].reduce(function (acc, curr) {
  if (typeof acc[curr] == 'undefined') {
    acc[curr] = 1;
  } else {
    acc[curr] += 1;
  }

  return acc;
}, {});

// a == {2: 5, 4: 1, 5: 3, 9: 1}

39
acc[curr] ? acc[curr]++ : acc[curr] = 1;
pmandell

ขอบคุณวิธีแก้ปัญหาที่ดีมาก;) ... และเพื่อรับอาร์เรย์ "คีย์" และ "ค่า":const keys = Object.keys(a); const values = Object.values(a);
ncenerar

79

หากใช้ขีดล่างหรือ Lodash นี่เป็นวิธีที่ง่ายที่สุดที่จะทำ:

_.countBy(array);

ดังนั้น:

_.countBy([5, 5, 5, 2, 2, 2, 2, 2, 9, 4])
=> Object {2: 5, 4: 1, 5: 3, 9: 1}

ตามที่คนอื่น ๆ ชี้ให้เห็นคุณสามารถดำเนินการ_.keys()และ_.values()ทำงานกับผลลัพธ์เพื่อให้ได้ตัวเลขที่ไม่ซ้ำใครและเกิดขึ้นตามลำดับ แต่จากประสบการณ์ของฉันวัตถุดั้งเดิมนั้นจัดการได้ง่ายกว่ามาก


55

อย่าใช้สองอาร์เรย์สำหรับผลลัพธ์ใช้วัตถุ:

a      = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
result = { };
for(var i = 0; i < a.length; ++i) {
    if(!result[a[i]])
        result[a[i]] = 0;
    ++result[a[i]];
}

จากนั้นresultจะมีลักษณะดังนี้:

{
    2: 5,
    4: 1,
    5: 3,
    9: 1
}

47

วิธีการเกี่ยวกับตัวเลือก ECMAScript2015

const a = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];

const aCount = new Map([...new Set(a)].map(
    x => [x, a.filter(y => y === x).length]
));
aCount.get(5)  // 3
aCount.get(2)  // 5
aCount.get(9)  // 1
aCount.get(4)  // 1

ตัวอย่างนี้ส่งอาร์เรย์อินพุตไปยังตัวSetสร้างที่สร้างชุดของค่าที่ไม่ซ้ำกัน ไวยากรณ์การแพร่กระจายแล้วขยายค่าเหล่านี้เป็นอาร์เรย์ใหม่เพื่อให้เราสามารถเรียกmapและแปลนี้เป็นอาร์เรย์สองมิติของ[value, count]คู่ - คือโครงสร้างต่อไปนี้:

Array [
   [5, 3],
   [2, 5],
   [9, 1],
   [4, 1]
]

อาร์เรย์ใหม่จะถูกส่งผ่านไปยังตัวMapสร้างที่ทำให้เกิดวัตถุที่วนซ้ำได้ :

Map {
    5 => 3,
    2 => 5,
    9 => 1,
    4 => 1
}

สิ่งที่ดีเกี่ยวกับ Mapวัตถุก็คือว่ามันจะเก็บรักษาข้อมูลประเภท - นั่นคือจะบอกว่าaCount.get(5)จะกลับมา3แต่จะกลับมาaCount.get("5") undefinedนอกจากนี้ยังช่วยให้ค่า / ประเภทใด ๆที่ทำหน้าที่เป็นกุญแจสำคัญหมายถึงการแก้ปัญหานี้จะทำงานกับอาร์เรย์ของวัตถุ


คุณมีคำตอบที่ดีขึ้นสำหรับอาเรย์วัตถุหรือไม่? ฉันมีปัญหาในการพยายามแก้ไขมันสำหรับออบเจ็กต์อาเรย์ที่คุณเพิ่งสร้างอาเรย์ / แผนที่ / ชุดใหม่ที่คุณลบรายการที่ซ้ำกันและเพิ่มค่าใหม่สำหรับวัตถุสมมติว่า "ซ้ำซ้อนจำนวน: ค่า" ฉันจัดการเพื่อลบรายการที่ซ้ำกันในอาร์เรย์วัตถุที่ซ้อนกันของฉันจากคำตอบนี้stackoverflow.com/a/36744732
sharon gur

Setใช้การอ้างอิงวัตถุเพื่อความเป็นเอกลักษณ์และไม่มี API สำหรับการเปรียบเทียบวัตถุ"ที่คล้ายกัน" หากคุณต้องการใช้วิธีการนี้สำหรับงานดังกล่าวคุณจะต้องใช้ฟังก์ชันการลดระดับกลางที่รับประกันอาร์เรย์ของอินสแตนซ์ที่ไม่ซ้ำกัน มันไม่ได้มีประสิทธิภาพมากที่สุด แต่ผมใส่กันอย่างรวดเร็วตัวอย่างเช่นที่นี่
ทูต

ขอบคุณสำหรับคำตอบ! แต่จริง ๆ แล้วฉันแก้ไขมันได้เล็กน้อย lilttle แตกต่างกัน หากคุณสามารถดูคำตอบที่ฉันเพิ่มได้ที่นี่stackoverflow.com/a/43211561/4474900ฉันยกตัวอย่างสิ่งที่ฉันทำ มันทำงานได้ดีกรณีของฉันมีวัตถุที่ซับซ้อนที่ต้องเปรียบเทียบ ไม่ทราบเกี่ยวกับประสิทธิภาพของวิธีแก้ปัญหาของฉัน
ชารอนกูร์

8
สิ่งนี้อาจใช้โครงสร้างข้อมูลใหม่ที่ดี แต่มีรันไทม์ใน O ( ) ในขณะที่มีอัลกอริทึมง่าย ๆ มากมายที่นี่ที่จะแก้ไขใน O ( n )
raphinesse

41

ฉันคิดว่านี่เป็นวิธีที่ง่ายที่สุดในการนับเหตุการณ์ที่เกิดขึ้นด้วยค่าเดียวกันในอาเรย์

var a = [true, false, false, false];
a.filter(function(value){
    return value === false;
}).length

9
หรือa.filter(value => !value).lengthด้วยไวยากรณ์ js ใหม่
t3chb0t

ไม่ตอบคำถาม
Ry-

35

โซลูชัน ES6 บรรทัดเดียว คำตอบมากมายที่ใช้วัตถุเป็นแผนที่ แต่ฉันไม่เห็นใครใช้แผนที่จริง

const map = arr.reduce((acc, e) => acc.set(e, (acc.get(e) || 0) + 1), new Map());

ใช้map.keys()เพื่อรับองค์ประกอบที่ไม่ซ้ำกัน

ใช้map.values()เพื่อรับสิ่งที่เกิดขึ้น

ใช้map.entries()เพื่อรับคู่ [องค์ประกอบ, ความถี่]

var arr = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4]

const map = arr.reduce((acc, e) => acc.set(e, (acc.get(e) || 0) + 1), new Map());

console.info([...map.keys()])
console.info([...map.values()])
console.info([...map.entries()])


Javascript สมัยใหม่ได้รับสิ่งที่ดีที่สุดจากทั่วทุกมุมโลก
Igniter

30

const data = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4]

function count(arr) {
  return arr.reduce((prev, curr) => (prev[curr] = ++prev[curr] || 1, prev), {})
}

console.log(count(data))


4
มีใครสนใจที่จะอธิบายเรื่องนี้ (prev [curr] = ++ prev [curr] || 1, prev)
Souljacker

6
ตัวดำเนินการเครื่องหมายจุลภาค “ ประเมินตัวถูกดำเนินการแต่ละตัว (จากซ้ายไปขวา) และส่งกลับค่าของตัวถูกดำเนินการล่าสุด” ดังนั้นการเพิ่มค่าของ prev [curr] (หรือเริ่มต้นที่ 1) จากนั้นส่งกลับ prev
ChrisV

แต่ผลลัพธ์คืออาร์เรย์?
Francesco

20

หากคุณชอบซับเดี่ยว

arr.reduce(function(countMap, word) {countMap[word] = ++countMap[word] || 1;return countMap}, {});

แก้ไข (6/12/2558) : คำอธิบายจากภายในสู่ภายนอก countMap เป็นแผนที่ที่แมปคำด้วยความถี่ซึ่งเราสามารถเห็นฟังก์ชั่นที่ไม่ระบุชื่อ สิ่งที่ลดลงจะใช้ฟังก์ชันที่มีอาร์กิวเมนต์เป็นองค์ประกอบอาร์เรย์และ countMap ทั้งหมดที่ถูกส่งผ่านเป็นค่าส่งคืนของการเรียกใช้ฟังก์ชันล่าสุด พารามิเตอร์สุดท้าย ({}) คือค่าดีฟอลต์ของ countMap สำหรับการเรียกใช้ฟังก์ชันแรก


1
คุณควรอธิบายสิ่งนี้ ที่จะทำให้มันเป็นคำตอบที่ดีกว่ามากเพื่อให้ผู้คนสามารถเรียนรู้วิธีการใช้ในกรณีการใช้งานอื่น ๆ
Andrew Grothe

ซับเดียวที่เพิ่งเอา LINEBREAK ที่มักจะทำตาม;, และ{ }... ตกลง. ฉันคิดว่าด้วยคำจำกัดความของหนึ่งสายการบินที่เราสามารถเขียนเกมแห่งชีวิตของคอนเวย์เป็น "oneliner"
trincot

16

รุ่น ES6 น่าจะมากพอสมควร (อีกโซลูชันหนึ่งบรรทัด)

let arr = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
let acc = arr.reduce((acc, val) => acc.set(val, 1 + (acc.get(val) || 0)), new Map());

console.log(acc);
// output: Map { 5 => 3, 2 => 5, 9 => 1, 4 => 1 }

แผนที่แทนที่จะเป็นวัตถุธรรมดาช่วยให้เราแยกแยะองค์ประกอบประเภทต่าง ๆ ไม่เช่นนั้นการนับทั้งหมดจะขึ้นอยู่กับสตริง


8

หากคุณใช้เครื่องหมายขีดล่างคุณสามารถไปยังเส้นทางที่ใช้งานได้

a = ['foo', 'foo', 'bar'];

var results = _.reduce(a,function(counts,key){ counts[key]++; return counts },
                  _.object( _.map( _.uniq(a), function(key) { return [key, 0] })))

ดังนั้นอาร์เรย์แรกของคุณคือ

_.keys(results)

และอาร์เรย์ที่สองคือ

_.values(results)

ส่วนใหญ่จะใช้ฟังก์ชันจาวาสคริปต์ดั้งเดิมหากมีให้ใช้งาน

ตัวอย่าง: http://jsfiddle.net/dAaUU/


8

จากคำตอบของ@adamseและ@pmandell (ซึ่งฉัน upvote) ในES6คุณสามารถทำได้ในหนึ่งบรรทัด :

  • แก้ไข 2017 : ฉันใช้||เพื่อลดขนาดรหัสและทำให้อ่านง่ายขึ้น

var a=[7,1,7,2,2,7,3,3,3,7,,7,7,7];
alert(JSON.stringify(

a.reduce((r,k)=>{r[k]=1+r[k]||1;return r},{})

));


มันสามารถใช้ในการนับตัวอักษร :

var s="ABRACADABRA";
alert(JSON.stringify(

s.split('').reduce((a, c)=>{a[c]++?0:a[c]=1;return a},{})

));


มันจะอ่านง่ายขึ้นถ้าคุณใช้|| 0:(r,k)=>{r[k]=(r[k]||0)+1;return r}
12Me21

คุณสามารถทำอะไรก็ได้ในบรรทัดเดียวใน JavaScript
Ry-

และทำไมมันถึงเป็นเรื่องไม่ดี @ Ry-?
ESL

บางครั้งก็ชัดเจนมากขึ้นในหลายบรรทัดอื่น ๆ ที่ชัดเจนในหนึ่งบรรทัด แม้ว่ามันจะเป็นเรื่องของ "รสนิยม"
ESL

ฉันหมายถึง“ ใน ES6 คุณสามารถทำได้ในหนึ่งบรรทัด” ใช้ได้กับทุกคำตอบและคุณสามารถทำได้ใน ES5 ในหนึ่งบรรทัด
Ry-

5

นี่คือสิ่งที่เบาและง่ายสำหรับดวงตา ...

function count(a,i){
 var result = 0;
 for(var o in a)
  if(a[o] == i)
   result++;
 return result;
}

แก้ไข:และเนื่องจากคุณต้องการให้เกิดขึ้นทั้งหมด ...

function count(a){
 var result = {};
 for(var i in a){
  if(result[a[i]] == undefined) result[a[i]] = 0;
  result[a[i]]++;
 }
 return result;
}

1
คำถามที่ถามถึงการนับองค์ประกอบทั้งหมด
Ry-

ตกลงพลาดนั่น ควรได้รับการแก้ไขแล้ว
ElDoRado1239

5

ดังนั้นนี่คือวิธีที่ฉันจะทำกับคุณสมบัติใหม่ล่าสุดของจาวาสคริปต์:

ก่อนอื่นลดอาร์เรย์ให้เหลือ a Map:

let countMap = array.reduce(
  (map, value) => {map.set(value, (map.get(value) || 0) + 1); return map}, 
  new Map()
)

ด้วยการใช้ a Map, อาร์เรย์เริ่มต้นของคุณสามารถมีวัตถุประเภทใดก็ได้และจำนวนนั้นจะถูกต้อง หากไม่มีMapวัตถุบางประเภทจะทำให้คุณมีค่าแปลก ๆ ดูMapเอกสารสำหรับข้อมูลเพิ่มเติมเกี่ยวกับความแตกต่าง

สิ่งนี้สามารถทำได้กับวัตถุหากค่าทั้งหมดของคุณเป็นสัญลักษณ์ตัวเลขหรือสตริง:

let countObject = array.reduce(
  (map, value) => { map[value] = (map[value] || 0) + 1; return map },
  {}
)

หรือผู้ที่ชื่นชอบเล็กน้อยในวิธีการทำงานโดยไม่มีการกลายพันธุ์โดยใช้ destructuring และการแพร่กระจายของวัตถุไวยากรณ์:

let countObject = array.reduce(
  (value, {[value]: count = 0, ...rest}) => ({ [value]: count + 1, ...rest }),
  {}
)

ณ จุดนี้คุณสามารถใช้ Mapหรือวัตถุสำหรับการนับของคุณ (และแผนที่สามารถทำซ้ำได้โดยตรงไม่เหมือนวัตถุ) หรือแปลงเป็นสองอาร์เรย์

สำหรับMap:

countMap.forEach((count, value) => console.log(`value: ${value}, count: ${count}`)

let values = countMap.keys()
let counts = countMap.values()

หรือวัตถุ:

Object
  .entries(countObject) // convert to array of [key, valueAtKey] pairs
  .forEach(([value, count]) => console.log(`value: ${value}, count: ${count}`)

let values = Object.keys(countObject)
let counts = Object.values(countObject)

4
var array = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];

function countDuplicates(obj, num){
  obj[num] = (++obj[num] || 1);
  return obj;
}

var answer = array.reduce(countDuplicates, {});
// answer => {2:5, 4:1, 5:3, 9:1};

หากคุณยังต้องการสองอาร์เรย์คุณสามารถใช้คำตอบเช่นนี้ ...

var uniqueNums = Object.keys(answer);
// uniqueNums => ["2", "4", "5", "9"];

var countOfNums = Object.keys(answer).map(key => answer[key]);
// countOfNums => [5, 1, 3, 1];

หรือถ้าคุณต้องการให้ตัวเลขไม่ซ้ำใคร

var uniqueNums = Object.keys(answer).map(key => +key);
// uniqueNums => [2, 4, 5, 9];

1
es6 / 7 ทำให้สิ่งนี้ดีกว่ามาก คุณอาจต้องการลดการ a Mapแทนเนื่องจากมันจะหลีกเลี่ยง typecasting ที่ใช้หมายเลขเป็นวัตถุคีย์ (หล่อเป็นสตริง) const answer = array.reduce((a, e) => a.set(e, (a.get(e) || 0) + 1), new Map()). คุณสามารถรับanswer.keys()กุญแจและanswer.values()ค่าเป็นอาร์เรย์ [...answer]จะให้อาร์เรย์จำนวนมากพร้อมคีย์ / ค่าทั้งหมดเป็นอาร์เรย์ 2d
Josh จาก Qaribou

4

โซลูชัน ES6 พร้อมการลด (คงที่):

const arr = [2, 2, 2, 3, 2]

const count = arr.reduce((pre, cur) => (cur === 2) ? ++pre : pre, 0)
console.log(count) // 4


ไม่แน่ใจว่าจำนวนหนึ่งแทนจำนวนขององค์ประกอบอาร์เรย์ที่แตกต่างกันเช่นคำถามที่ถาม
Ry-

4

แก้ไข 2020 : นี่เป็นคำตอบที่ค่อนข้างเก่า (เก้าปี) ขยายพื้นเมืองprototypeมักจะสร้างการอภิปราย แม้ว่าฉันคิดว่าโปรแกรมเมอร์มีอิสระที่จะเลือกรูปแบบการเขียนโปรแกรมของเธอเอง แต่นี่เป็นวิธีการ (ที่ทันสมัยกว่า) สำหรับปัญหาโดยไม่ขยายArray.prototype:

{
  // create array with some pseudo random values (1 - 5)
  const arr = Array.from({length: 100})
    .map( () => Math.floor(1 + Math.random() * 5) );
  // frequencies using a reducer
  const arrFrequencies = arr.reduce((acc, value) => 
      ({ ...acc, [value]: acc[value] + 1 || 1}), {} )
  console.log(`Value 4 occurs ${arrFrequencies[4]} times in arrFrequencies`);

  // bonus: restore Array from frequencies
  const arrRestored = Object.entries(arrFrequencies)
    .reduce( (acc, [key, value]) => acc.concat(Array(value).fill(+key)), [] );
  console.log(arrRestored.join());  
}
.as-console-wrapper { top: 0; max-height: 100% !important; }

คำตอบเก่า (2011): คุณสามารถขยายArray.prototypeได้เช่นนี้



2

โซลูชันที่ใช้แผนที่พร้อมความซับซ้อนของเวลาO (n)

var arr = [2, 2, 2, 2, 2, 4, 5, 5, 5, 9];

const countOccurrences = (arr) => {
    const map = {};
    for ( var i = 0; i < arr.length; i++ ) {
        map[arr[i]] = ~~map[arr[i]] + 1;
    }
    return map;
}

ตัวอย่าง: http://jsfiddle.net/simevidas/bnACW/


การลงคะแนนของฉันสำหรับคุณงานนี้เหมือนเนยที่มีความซับซ้อนของเวลา O (n)
Vishal Shetty


1

การใช้MAPคุณสามารถมี 2 อาร์เรย์ในผลลัพธ์: อันหนึ่งที่มีเหตุการณ์เกิดขึ้นและอีกอันหนึ่งมีจำนวนครั้งที่เกิดขึ้น

const dataset = [2,2,4,2,6,4,7,8,5,6,7,10,10,10,15];
let values = [];
let keys = [];

var mapWithOccurences = dataset.reduce((a,c) => {
  if(a.has(c)) a.set(c,a.get(c)+1);
  else a.set(c,1);
  return a;
}, new Map())
.forEach((value, key, map) => {
  keys.push(key);
  values.push(value);
});


console.log(keys)
console.log(values)


0

ตรวจสอบรหัสด้านล่าง

<html>
<head>
<script>
// array with values
var ar = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];

var Unique = []; // we'll store a list of unique values in here
var Counts = []; // we'll store the number of occurances in here

for(var i in ar)
{
    var Index = ar[i];
    Unique[Index] = ar[i];
    if(typeof(Counts[Index])=='undefined')  
        Counts[Index]=1;
    else
        Counts[Index]++;
}

// remove empty items
Unique = Unique.filter(function(){ return true});
Counts = Counts.filter(function(){ return true});

alert(ar.join(','));
alert(Unique.join(','));
alert(Counts.join(','));

var a=[];

for(var i=0; i<Unique.length; i++)
{
    a.push(Unique[i] + ':' + Counts[i] + 'x');
}
alert(a.join(', '));

</script>
</head>
<body>

</body>
</html>

0

ลองสิ่งนี้:

Array.prototype.getItemCount = function(item) {
    var counts = {};
    for(var i = 0; i< this.length; i++) {
        var num = this[i];
        counts[num] = counts[num] ? counts[num]+1 : 1;
    }
    return counts[item] || 0;
}

0

ฉันกำลังแก้ไขปัญหาที่คล้ายกันใน codewars และคิดค้นวิธีแก้ไขปัญหาต่อไปนี้ซึ่งเหมาะกับฉัน

สิ่งนี้จะให้จำนวนสูงสุดของจำนวนเต็มในอาร์เรย์และจำนวนเต็มเอง ฉันคิดว่ามันสามารถใช้กับอาร์เรย์สตริงได้เช่นกัน

หากต้องการจัดเรียงสตริงอย่างถูกต้องให้ลบออกfunction(a, b){return a-b}จากภายในsort()ส่วน

function mostFrequentItemCount(collection) {
    collection.sort(function(a, b){return a-b});
    var i=0;
    var ans=[];
    var int_ans=[];
    while(i<collection.length)
    {
        if(collection[i]===collection[i+1])
        {
            int_ans.push(collection[i]);
        }
        else
        {
            int_ans.push(collection[i]);
            ans.push(int_ans);
            int_ans=[];
        }
        i++;
    }

    var high_count=0;
    var high_ans;

    i=0;
    while(i<ans.length)
    {
        if(ans[i].length>high_count)
        {
            high_count=ans[i].length;
            high_ans=ans[i][0];
        }
        i++;
    }
    return high_ans;
}

0

นี่คือวิธีการนับเหตุการณ์ที่เกิดขึ้นภายในอาร์เรย์ของวัตถุ นอกจากนี้ยังวางเนื้อหาของอาร์เรย์แรกไว้ในอาร์เรย์ใหม่เพื่อเรียงลำดับค่าเพื่อให้ลำดับในอาร์เรย์เดิมไม่ถูกรบกวน จากนั้นฟังก์ชั่นวนซ้ำจะใช้ในการผ่านแต่ละองค์ประกอบและนับคุณสมบัติปริมาณของแต่ละวัตถุภายในอาร์เรย์

var big_array = [
  { name: "Pineapples", quantity: 3 },
  { name: "Pineapples", quantity: 1 },
  { name: "Bananas", quantity: 1 },
  { name: "Limes", quantity: 1 },
  { name: "Bananas", quantity: 1 },
  { name: "Pineapples", quantity: 2 },
  { name: "Pineapples", quantity: 1 },
  { name: "Bananas", quantity: 1 },
  { name: "Bananas", quantity: 1 },
  { name: "Bananas", quantity: 5 },
  { name: "Coconuts", quantity: 1 },
  { name: "Lemons", quantity: 2 },
  { name: "Oranges", quantity: 1 },
  { name: "Lemons", quantity: 1 },
  { name: "Limes", quantity: 1 },
  { name: "Grapefruit", quantity: 1 },
  { name: "Coconuts", quantity: 5 },
  { name: "Oranges", quantity: 6 }
];

function countThem() {
  var names_array = [];
  for (var i = 0; i < big_array.length; i++) {
    names_array.push( Object.assign({}, big_array[i]) );
  }

  function outerHolder(item_array) {
    if (item_array.length > 0) {
      var occurrences = [];
      var counter = 0;
      var bgarlen = item_array.length;
      item_array.sort(function(a, b) { return (a.name > b.name) ? 1 : ((b.name > a.name) ? -1 : 0); });

      function recursiveCounter() {
        occurrences.push(item_array[0]);
        item_array.splice(0, 1);
        var last_occurrence_element = occurrences.length - 1;
        var last_occurrence_entry = occurrences[last_occurrence_element].name;
        var occur_counter = 0;
        var quantity_counter = 0;
        for (var i = 0; i < occurrences.length; i++) {
          if (occurrences[i].name === last_occurrence_entry) {
            occur_counter = occur_counter + 1;
            if (occur_counter === 1) {
              quantity_counter = occurrences[i].quantity;
            } else {
              quantity_counter = quantity_counter + occurrences[i].quantity;
            }
          }
        }

        if (occur_counter > 1) {
          var current_match = occurrences.length - 2;
          occurrences[current_match].quantity = quantity_counter;
          occurrences.splice(last_occurrence_element, 1);
        }

        counter = counter + 1;

        if (counter < bgarlen) {
          recursiveCounter();
        }
      }

      recursiveCounter();

      return occurrences;
    }
  }
  alert(JSON.stringify(outerHolder(names_array)));
}

0
function countOcurrences(arr){
    return arr.reduce((aggregator, value, index, array) => {
      if(!aggregator[value]){
        return aggregator = {...aggregator, [value]: 1};  
      }else{
        return aggregator = {...aggregator, [value]:++aggregator[value]};
      }
    }, {})
}

สิ้นเปลืองอย่างมากในการคัดลอกวัตถุทุกครั้ง สร้างกรณีที่เลวร้ายที่สุดสมการกำลังสองเมื่อมันเป็นเส้นตรง
Ry-

0
var aa = [1,3,5,7,3,2,4,6,8,1,3,5,5,2,0,6,5,9,6,3,5,2,5,6,8];
var newArray = {};
for(var element of aa){
  if(typeof newArray[element] === 'undefined' || newArray[element] === null){
    newArray[element] = 1;
  }else{
    newArray[element] +=1;
  }
}

for ( var element in newArray){
  console.log( element +" -> "+ newArray[element]);
}

0

คำถามนี้มีอายุมากกว่า 8 ปีและอีกมากมายคำตอบมากมายไม่ได้คำนึงถึง ES6 และข้อดีมากมายของมัน

บางทีอาจสำคัญกว่าที่จะคิดเกี่ยวกับผลที่ตามมาของรหัสของเราสำหรับการรวบรวมขยะ / การจัดการหน่วยความจำเมื่อใดก็ตามที่เราสร้างอาร์เรย์เพิ่มเติมทำสำเนาอาร์เรย์สองหรือสามชุดหรือแม้แต่แปลงอาร์เรย์เป็นวัตถุ สิ่งเหล่านี้เป็นข้อสังเกตเล็กน้อยสำหรับการใช้งานขนาดเล็ก แต่หากขนาดเป็นเป้าหมายระยะยาว

หากคุณต้องการ "ตัวนับ" สำหรับชนิดข้อมูลเฉพาะและจุดเริ่มต้นคืออาร์เรย์ (ฉันถือว่าคุณต้องการรายการที่สั่งซื้อและใช้ประโยชน์จากคุณสมบัติและวิธีการมากมายที่มีอยู่ในอาร์เรย์) คุณสามารถทำซ้ำผ่าน array1 และ populate array2 ที่มีค่าและจำนวนการเกิดขึ้นสำหรับค่าเหล่านี้ที่พบใน array1

ง่ายเหมือนที่

ตัวอย่าง SimpleCounter คลาสอย่างง่าย (ES6) สำหรับการเขียนโปรแกรมเชิงวัตถุและการออกแบบเชิงวัตถุ

class SimpleCounter { 

    constructor(rawList){ // input array type
        this.rawList = rawList;
        this.finalList = [];
    }

    mapValues(){ // returns a new array

        this.rawList.forEach(value => {
            this.finalList[value] ? this.finalList[value]++ : this.finalList[value] = 1;
        });

        this.rawList = null; // remove array1 for garbage collection

        return this.finalList;

    }

}

module.exports = SimpleCounter;

การผสานฟังก์ชั่นในคลาสโดยไม่มีเหตุผลไม่ได้ทำให้มันเป็นวัตถุเชิงfinalListไม่มีเหตุผลที่จะเป็นอาร์เรย์และสิ่งนี้ไม่มีข้อได้เปรียบในการทำอย่างถูกต้อง
Ry-

-1

นี่คือวิธีการเรียนแบบเก่าแบบคลาสสิคสำหรับการนับอาร์เรย์

var arr = [5, 5, 5, 2, 2, 2, 2, 2, 9, 4];
var counted = [], count = [];
var i = 0, j = 0, k = 0;
while (k < arr.length) {
    if (counted.indexOf(arr[k]) < 0) {
        counted[i] = arr[k];
        count[i] = 0;
        for (j = 0; j < arr.length; j++) {
            if (counted[i] == arr[j]) {
                count[i]++;
            }
        }
        i++;
    } else {
        k++;
    }
}

คุณสามารถเรียงลำดับก่อนถ้าคุณต้องการผลลัพธ์ตามตัวอักษร แต่ถ้าคุณต้องการรักษาลำดับที่ข้อมูลถูกป้อนให้ลองทำเช่นนี้ ลูปซ้อนอาจช้ากว่าวิธีอื่น ๆ ในหน้านี้เล็กน้อย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.