จะหาดัชนีขององค์ประกอบทั้งหมดในอาร์เรย์ได้อย่างไร?


111

ฉันกำลังพยายามค้นหาดัชนีของอินสแตนซ์ทั้งหมดขององค์ประกอบที่พูดว่า "นาโน" ในอาร์เรย์ JavaScript

var Cars = ["Nano", "Volvo", "BMW", "Nano", "VW", "Nano"];

ฉันลองใช้jQuery.inArrayหรือในทำนองเดียวกันคือ . indexOf ()แต่ให้ดัชนีของอินสแตนซ์สุดท้ายขององค์ประกอบเท่านั้นเช่น 5 ในกรณีนี้

ฉันจะรับมันสำหรับอินสแตนซ์ทั้งหมดได้อย่างไร

คำตอบ:


117

.indexOf()วิธีมีพารามิเตอร์ที่สองตัวเลือกที่ระบุดัชนีเพื่อเริ่มต้นการค้นหาจากเพื่อให้คุณสามารถเรียกมันในวงที่จะหาทุกกรณีของค่าโดยเฉพาะอย่างยิ่ง

function getAllIndexes(arr, val) {
    var indexes = [], i = -1;
    while ((i = arr.indexOf(val, i+1)) != -1){
        indexes.push(i);
    }
    return indexes;
}

var indexes = getAllIndexes(Cars, "Nano");

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

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

function getAllIndexes(arr, val) {
    var indexes = [], i;
    for(i = 0; i < arr.length; i++)
        if (arr[i] === val)
            indexes.push(i);
    return indexes;
}

1
ดูเหมือนจะไม่ใช่ทางเลือกที่เร็วกว่าสำหรับforลูปเดียวที่มีดัชนีอาร์เรย์บรรจุอยู่
VisioN

1
@VisioN - ใช่ธรรมดาสำหรับการวนซ้ำบนอาร์เรย์ก็จะง่ายกว่าเช่นกัน แต่เนื่องจาก OP กล่าวถึงการพยายามใช้.indexOf()ฉันจึงต้องการแสดงให้เห็นว่ามันสามารถทำงานได้ (ฉันเดาว่าฉันคิดว่า OP สามารถหาวิธีทำกับลูปได้) แน่นอนว่ามีวิธีอื่นในการทำเช่นCars.reduce(function(a, v, i) { if (v==="Nano") a.push(i); return a; }, []);
nnnnnn

ฉันบอกได้เลยว่าคุณมาจากอเมริกาเหนือเพราะคุณใช้indexesแทนindices: P
4castle

2
@ 4castle - ฮะ. ไม่ฉันไม่ใช่. "ดัชนี" และ "ดัชนี" ถูกต้องทั้งคู่และฉันมักจะสลับระหว่างทั้งสอง ฉันไม่เคยคิดมาก่อนว่าเป็นภาษาถิ่น น่าสนใจ.
nnnnnn

โปรดทราบว่าตัวอย่างแรกใช้งานได้ดีสำหรับสตริงและอาร์เรย์ อย่างที่สองใช้ได้กับอาร์เรย์เท่านั้น
SethWhite

82

อีกทางเลือกหนึ่งคือการใช้Array.prototype.reduce():

["Nano","Volvo","BMW","Nano","VW","Nano"].reduce(function(a, e, i) {
    if (e === 'Nano')
        a.push(i);
    return a;
}, []);   // [0, 3, 5]

หมายเหตุ:ตรวจสอบความเข้ากันได้ของเบราว์เซอร์สำหรับreduceวิธีการและใช้polyfillหากจำเป็น


2
+1. เรื่องบังเอิญตลก: ฉันเพิ่งแก้ไขการตอบกลับความคิดเห็นของคุณภายใต้คำตอบของฉันเพื่อแนะนำวิธีแก้ปัญหานี้จากนั้นฉันรีเฟรชและเห็นว่าคุณได้เข้ารหัสสิ่งเดียวกันแล้วโดยมีชื่อตัวแปรเพียงตัวเดียวที่แตกต่างกัน
nnnnnn

@nnnnnn :)ใช่ฉันคิดว่าอาจreduceจะเป็นทางเลือกที่ดี
VisioN

26
array.reduce((a, e, i) => (e === value) ? a.concat(i) : a, [])
yckart

ฉัน googled contatช้ากว่าpushดังนั้นฉันจึงยึดติดกับคำตอบ
Andre Elrico

55

อีกวิธีหนึ่งโดยใช้Array.prototype.map ()และArray.prototype.filter () :

var indices = array.map((e, i) => e === value ? i : '').filter(String)

3
เยี่ยมมากมันใช้งานได้ คุณช่วยอธิบายได้ไหมว่าบทบาทของตัวกรอง (String)
อะไร

3
@Muthu map(…)ตรวจสอบการทำซ้ำแต่ละครั้งเพื่อความเท่าเทียมกันของeและvalue. เมื่อตรงกับดัชนีจะถูกส่งกลับมิฉะนั้นสตริงว่างเปล่า ในการกำจัดค่าเท็จเหล่านั้นfilter(String)ตรวจสอบให้แน่ใจว่าผลลัพธ์มีเฉพาะค่าที่เป็นประเภทสตริงเท่านั้นและไม่ว่างเปล่า filter(String)สามารถเขียนได้ว่า:filter(e => e !== '')
yckart

3
... หรือ: String(thing)บังคับทุกอย่างให้เป็นสตริง Array#filterส่งกลับอาร์เรย์ของค่าทั้งหมดที่อยู่ในสภาพที่เป็นtruthy เนื่องจากสตริงว่างเป็นเท็จจึงไม่รวมอยู่ในอาร์เรย์
yckart

ขอบคุณสำหรับคำอธิบายมันมีประโยชน์มากสำหรับฉัน
Muthamizhchelvan V

2
ฉันจะงงถ้าเห็นสิ่งนี้ในโครงการ มันอ่านว่า "Filter to strings" หมายถึงเก็บไว้ถ้าเป็นสตริงเท่านั้น จากนั้นอาร์เรย์ผลลัพธ์จะถูกสร้างดัชนีเป็นสตริงไม่ใช่ตัวเลข
Michael Pearson

14

วิธีที่ง่ายกว่าด้วยสไตล์ es6

const indexOfAll = (arr, val) => arr.reduce((acc, el, i) => (el === val ? [...acc, i] : acc), []);


//Examples:
var cars = ["Nano", "Volvo", "BMW", "Nano", "VW", "Nano"];
indexOfAll(cars, "Nano"); //[0, 3, 5]
indexOfAll([1, 2, 3, 1, 2, 3], 1); // [0,3]
indexOfAll([1, 2, 3], 4); // []

12

คุณสามารถเขียนวิธีง่ายๆที่อ่านได้โดยใช้ทั้งสองอย่างmapและfilter:

const nanoIndexes = Cars
  .map((car, i) => car === 'Nano' ? i : -1)
  .filter(index => index !== -1);

แก้ไข: หากคุณไม่ต้องการที่จะสนับสนุน IE / ขอบ (หรือ transpiling รหัสของคุณ) ES2019 ให้เราflatMapซึ่งจะช่วยให้คุณทำเช่นนี้ในการที่ง่ายหนึ่งซับ:

const nanoIndexes = Cars.flatMap((car, i) => car === 'Nano' ? i : []);


5

ฉันแค่ต้องการอัปเดตด้วยวิธีง่ายๆอื่น ๆ

คุณยังสามารถใช้ forEach method

var Cars = ["Nano", "Volvo", "BMW", "Nano", "VW", "Nano"];

var result = [];

Cars.forEach((car, index) => car === 'Nano' ? result.push(index) : null)

3
const indexes = cars
    .map((car, i) => car === "Nano" ? i : null)
    .filter(i => i !== null)

1
ดัชนีจะอิงตามศูนย์ดังนั้นจะล้มเหลวหากรถคันแรกเป็นนาโน
Zac Delventhal

1
ดูสิคุณมีวิธีแก้ปัญหาและของฉันก็ดูเหมือนมัน ฉันควรจะได้เห็นคุณก่อนที่ฉันจะใช้เวลาเขียนของฉัน มีการแผ่กิ่งก้านสาขามากมายสำหรับการวนซ้ำฉันคิดว่า "ฉันสามารถตอบคำถามของตัวเองได้ใน 2 วินาที"
Michael Pearson

ใช่. สิ่งเหล่านี้ส่วนใหญ่ซับซ้อนเกินไป การแก้ไขที่ดี
Zac Delventhal

2

สิ่งนี้ใช้ได้ผลสำหรับฉัน:

let array1 = [5, 12, 8, 130, 44, 12, 45, 12, 56];
let numToFind = 12
let indexesOf12 = [] // the number whose occurrence in the array we want to find

array1.forEach(function(elem, index, array) {
    if (elem === numToFind) {indexesOf12.push(index)}
    return indexesOf12
})

console.log(indexesOf12) // outputs [1, 5, 7]

1

เพื่อแบ่งปันวิธีการอื่นคุณสามารถใช้Function Generatorsเพื่อให้ได้ผลลัพธ์เช่นกัน:

function findAllIndexOf(target, needle) {
  return [].concat(...(function*(){
    for (var i = 0; i < target.length; i++) if (target[i] === needle) yield [i];
  })());
}

var target = "hellooooo";
var target2 = ['w','o',1,3,'l','o'];

console.log(findAllIndexOf(target, 'o'));
console.log(findAllIndexOf(target2, 'o'));


0

เราสามารถใช้ Stack แล้วดัน "i" เข้าไปใน stack ได้ทุกครั้งที่เจอเงื่อนไข "arr [i] == value"

ตรวจสอบสิ่งนี้:

static void getindex(int arr[], int value)
{
    Stack<Integer>st= new Stack<Integer>();
    int n= arr.length;
    for(int i=n-1; i>=0 ;i--)
    {
        if(arr[i]==value)
        {
            st.push(i);
        }
    }   
    while(!st.isEmpty())
    {
        System.out.println(st.peek()+" ");
        st.pop(); 
    }
}

2
คำถามถูกแท็กด้วยjavascriptในขณะที่คำตอบของคุณคือJavaฉันเชื่อ?
noggin182

0
["a", "b", "a", "b"]
   .map((val, index) => ({ val, index }))
   .filter(({val, index}) => val === "a")
   .map(({val, index}) => index)

=> [0, 2]

โปรดเขียนคำอธิบายที่จำเป็นหรือความคิดเห็นแบบอินไลน์สำหรับโค้ด BTW โซลูชันของคุณใช้งานได้ แต่มีการทำซ้ำ 3 ครั้ง ...
JustWe

0

คุณสามารถใช้ Polyfill

if (!Array.prototype.filterIndex) {
Array.prototype.filterIndex = function (func, thisArg) {

    'use strict';
    if (!((typeof func === 'Function' || typeof func === 'function') && this))
        throw new TypeError();

    let len = this.length >>> 0,
        res = new Array(len), // preallocate array
        t = this, c = 0, i = -1;

    let kValue;
    if (thisArg === undefined) {
        while (++i !== len) {
            // checks to see if the key was set
            if (i in this) {
                kValue = t[i]; // in case t is changed in callback
                if (func(t[i], i, t)) {
                    res[c++] = i;
                }
            }
        }
    }
    else {
        while (++i !== len) {
            // checks to see if the key was set
            if (i in this) {
                kValue = t[i];
                if (func.call(thisArg, t[i], i, t)) {
                    res[c++] = i;
                }
            }
        }
    }

    res.length = c; // shrink down array to proper size
    return res;
};

}

ใช้แบบนี้:

[2,23,1,2,3,4,52,2].filterIndex(element => element === 2)

result: [0, 3, 7]

-1

findIndexดึงเฉพาะดัชนีแรกที่ตรงกับเอาต์พุตการเรียกกลับ คุณสามารถใช้งานของคุณเองได้findIndexesโดยการขยาย Array จากนั้นส่งอาร์เรย์ของคุณไปยังโครงสร้างใหม่

class EnhancedArray extends Array {
  findIndexes(where) {
    return this.reduce((a, e, i) => (where(e, i) ? a.concat(i) : a), []);
  }
}
   /*----Working with simple data structure (array of numbers) ---*/

//existing array
let myArray = [1, 3, 5, 5, 4, 5];

//cast it :
myArray = new EnhancedArray(...myArray);

//run
console.log(
   myArray.findIndexes((e) => e===5)
)
/*----Working with Array of complex items structure-*/

let arr = [{name: 'Ahmed'}, {name: 'Rami'}, {name: 'Abdennour'}];

arr= new EnhancedArray(...arr);


console.log(
  arr.findIndexes((o) => o.name.startsWith('A'))
)


-1

หากคุณตั้งใจจะใช้เครื่องหมายขีดล่าง / lodash คุณสามารถทำได้

var Cars = ["Nano", "Volvo", "BMW", "Nano", "VW", "Nano"];

_.chain(Cars).map((v, i)=> [i, v === "Nano"]).filter(v=>v[1]).map(v=>v[0]).value()

[0, 3, 5]

2
คุณไม่ต้องการห้องสมุดสำหรับสิ่งนั้นจริงๆ:(["Nano", "Volvo", "BMW", "Nano", "VW", "Nano"]).map((v, i)=> [i, v === "Nano"]).filter(v=>v[1]).map(v=>v[0])
edjroot
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.