admin管理员组

文章数量:1134247

I have an array of objects in my angular controller.

I want to return the value of the index of the field within the array which has a matching ID to my parameter.

There will only be one object in the array with a matching fieldId..

$scope.indexOfField = function(fieldId) {
  return $scope.model.fieldData.filter(function(x) {
    if (x.Id === fieldId) return // ???????
  });
}

I have an array of objects in my angular controller.

I want to return the value of the index of the field within the array which has a matching ID to my parameter.

There will only be one object in the array with a matching fieldId..

$scope.indexOfField = function(fieldId) {
  return $scope.model.fieldData.filter(function(x) {
    if (x.Id === fieldId) return // ???????
  });
}
Share Improve this question edited Apr 16, 2021 at 18:50 serraosays 7,8293 gold badges38 silver badges67 bronze badges asked Oct 20, 2014 at 14:50 user4079725user4079725 1
  • This is not an angujarjs question, but a general javascript one, so I would remove the angularjs tag. But it's an interesting question anyway, because other languages have methods to handle this. See my answer below, where I implement a withIndex method in Array. – Ferran Maylinch Commented May 3, 2018 at 20:46
Add a comment  | 

15 Answers 15

Reset to default 103

The .findIndex() method returns the index of the first element of the array that satisfies a condition given by a function. If the function returns false for all elements of the array, the result is -1.

See the documentation here.

In my example, x is an item for each iteration and I use cross function for my condition.

const datas = [];
const fieldId = 5;
let index = datas.findIndex( x => x.Id === fieldId );

You can't return index from filter method.

The filter() method creates a new array with all elements that pass the test implemented by the provided function.

You can use forEach

$scope.indexOfField = function(fieldId) {
    var i;
    return $scope.model.fieldData.forEach(function(x, index) {
        if (x.Id === fieldId) {
            i = index;
        }
    });
    // use i
}

or even better to use for as you can't stop forEach when you have found your id.

$scope.indexOfField = function(fieldId) {
    var fieldData = $scope.model.fieldData, 
        i = 0, ii = $scope.model.fieldData.length;
    for(i; i < ii; i++) if(fieldData[i].Id === fieldId) break;
    // use i
}

ARRAY (FIND MULTIPLE INDEXES) METHOD

[10, 7, 13, 15, 230].map((e,i) => e > 13 ? i : undefined).filter(x => x) 
      //returns [3, 4](*** RETURNS multiple indexes ***)
      //FILTER (is simply just REMOVING the UNDEFINED elements (which are FALSY and considered the same as FALSE)

otherwise you'll get...

[10, 7, 13, 15, 230].map((e,i) => e > 13 ? i : undefined)  //returns [undefined, undefined, undefined, 3, 4]

RETURN MULTIPLE INDEXES (replaces findIndex METHOD)

[1, 1, 2, 2, 2, 3, 4, 5].map((e,i) => e === 2 ? i : undefined).filter(x => x) //returns [2, 3, 4]

RETURN MULTIPLE VALUES (replaces find METHOD)

[5, 12, 8, 130, 44].map((e,i) => e > 13 ? e : undefined).filter(x => x) // returns [130, 44]

From the Array.prototype.filter documentation:

callback is invoked with three arguments:

  • the value of the element
  • the index of the element
  • the Array object being traversed

However you should probably be using the some function if there is only one instance in your array (as it will stop as soon as it finds the first occurrence), and then find the index using indexOf:

var field = $scope.model.fieldData.filter(function(x) {
    return x.Id === fieldId;
})[0];
var index = $scope.model.fieldData.indexOf(field);

Or iterate the array until you find the correct element:

var index;
$scope.model.fieldData.some(function(x, i) {
    if (x.Id === fieldId) return (index = i);
});

The second argument to your callback is the index. I can't quite make out what you want your function to do/return, but if you add , index after function(x, that will give you access to the index for that iteration.

Working from the name of your function, I don't think you want filter at all:

$scope.indexOfField = function(fieldId) {
    var result = -1;
    $scope.model.fieldData.some(function(x, index) {
        if (x.Id === fieldId) {
            result = index;
            return true;
        }
    });
    return result;
}

Array#some stops as of the first iteration that returns a truthy value, so we'll stop searching the first time we find a match.

Use the findIndex method - Array.prototype.findIndex().

When the condition is met first, the index is returned.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex

You cannot return directly the index but you can set the 'thisArg' parameter and set data inside it. This is cleaner than a global variable.

var data = {
    indexes: []
};
var myArray = [1,2,3,4,5,6,7,8,9,10];

myArray.filter(function (element, index) {
    if (element%2 == 0) {
        this.indexes.push(index);
        return true;
    }
}, data);

console.log(data.indexes); // [1, 3, 5, 7, 9]
data.indexes.forEach(function(value) {
    console.log(myArray[value]);
}); // 2, 4, 6, 8, 10

Try flatMap(), with or without i.

[5, 12, 8, 130, 44].flatMap((e, i) => (e > 13 ? e : [])); // returns [130, 44]

You most definitely can (ahem, guy who got accepted answer)

const polyfillter = (arr,condition) => arr.map( (e,i) => condition ? i : -1).filter(e=>e>=0)    

Pass in an array, and your condition, and get back matching keys.

example

mynewstuff = polyfillter(myoldcrud, "e.length > 5")

Some languages can map a collection into an indexed collection where each element is mapped to a pair of {element, index}. That way you can map/filter/etc using any of those two values.

For example, Kotlin has withIndex and Swift has enumerated.

Javascript doesn't have that method, AFAIK. But you can easily build yours or use a workaround.

Workaround (not recommended)

// Turn an array of elements into an array of {value, index}
const indexedArray = array.map((v,i) => ({value:v, index:i}));
// Now I can filter by the elem but keep the index in the result
const found = array.filter(x => x.value === someValue)[0];
if (found) {
    console.log(`${found.value} found at index ${found.index}`);
}

// One-liner for the question scenario, using some new js features.
// Note that this will fail at the last ".i" if the object is not found.
const index = fieldData.map((v,i) => ({v,i})).filter(x => x.v.id == fieldId)[0].i

Add a withIndex method to Array (recommended):

This is basically the same as the workaround, but creating a reusable function, which makes it much cleaner.

Array.prototype.withIndex = function() {
    return this.map((v,i) => ({value: v, index: i}))
};

// Now the one-liner would be:
const index = fieldData.withIndex().filter(x => x.value.id == fieldId)[0].index;

// Better, with null checking:
const found = fieldData.withIndex().filter(x => x.value.id == fieldId)[0];
if (found) {
    console.log(`${found.value} found at index ${found.index}`);
}

If there is only one object returned you can simply use the original array to refer to the returned object.

Since filter returns an array, you can do as follows

$scope.indexOfField = function(fieldId) {
    var filteredArray = $scope.model.fieldData.filter(function(x) {
        return x.Id === fieldId
    });

    var desiredObject = filteredArray[0]
    return $scope.model.fieldData.indexOf(desiredObject);
}
['ab', 'cd', 'ef', 'id', 'junk', 'dummy','name'].map((x, ndx)=>['id', 'name'].includes(x)?ndx:'').filter(e=>e)

result: (2) [3, 6]

Filter will not return the index, but you can do something like this.

$scope.indexOfField = function(fieldId) {
    $scope.model.fieldData.filter(function(x, i) {
        if (x.Id === fieldId) {
            var indexOfField = i;
        }
    });
    return indexOfField;
};
$scope.indexOfField = function(fieldId) {
  let index;
  $scope.model.fieldData.filter((x, i) => {
    if (x.Id === fieldId) index = i;
    return x.Id === fieldId;
  });
  return index;
}
function modifyArray(nums) {
let newNums = nums.filter((num,index) => {
        return num = num % 2 ? num * 3 : num * 2; 
    })
  return newNums;
}

Here the index is the increment value you are looking for.

本文标签: arraysReturn index value from filter method javascriptStack Overflow