Skip to content

Commit

Permalink
Merge pull request #17 from tjmehta/find
Browse files Browse the repository at this point in the history
Add `find` and `findIndex`
  • Loading branch information
tjmehta committed Mar 17, 2016
2 parents 4c17e45 + 07d311a commit a7ef4b7
Show file tree
Hide file tree
Showing 8 changed files with 537 additions and 55 deletions.
174 changes: 122 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
object-loops [![Build Status](https://travis-ci.org/tjmehta/object-loops.svg)](https://travis-ci.org/tjmehta/object-loops)
============

Functional methods like forEach, map, filter, and other ES5 Array methods for Objects in javascript
Functional methods like forEach, map, filter, and other Array methods for Objects in javascript

# Installation

`npm install object-loops`

# Index

[chain](https://github.com/tjmehta/object-loops#usage)
[every](https://github.com/tjmehta/object-loops#every)
[find](https://github.com/tjmehta/object-loops#find)
[findKey](https://github.com/tjmehta/object-loops#findKey)
[filter](https://github.com/tjmehta/object-loops#filter)
[forEach](https://github.com/tjmehta/object-loops#forEach)
[map](https://github.com/tjmehta/object-loops#map)
[reduce](https://github.com/tjmehta/object-loops#reduce)
[some](https://github.com/tjmehta/object-loops#some)

# Usage

#### You can require each method individually `object-loops/<loop>`
Expand All @@ -17,6 +29,7 @@ var forEach = require('object-loops/for-each')
var mapKeys = require('object-loops/map-keys')
var map = require('object-loops/map')
var reduce = require('object-loops/reduce')
//... and more
// usage
forEach({ x:10, y: 20 }, callback)
filter({ x:10, y: 20 }, callback)
Expand Down Expand Up @@ -49,59 +62,87 @@ obj.map(callback)
obj.reduce(callback)
```

## every

## forEach

Executes a provided function once per each object value.
Tests whether every value in the object passes the test implemented by the callback.

* @param {object} [obj] - object to forEach, not accepted if being used directly on Object.prototype
* @param {function} callback - function that will be invoked once for each key-value pair
* @function module:object-loops/every
* @param {object} [obj] - object to iterate through, not accepted if being used directly on Object.prototype
* @param {everyCallback} callback - function to test each value in the object. return falsey to end the loop, truthy otherwise.
* @param {*} [thisArg] - optional. context to bind to callback
* @returns {boolean} if callback returns false, the loop is ended and false is returned (else false)

```js
var forEach = require('object-loops/for-each')
var every = require('object-loops/every')

var obj = {
foo: 10,
bar: 20,
baz: 30
baz: 30,
qux: 40,
}
var keyConcat = ''
var valSum = 0
forEach(obj, function (val, key, obj) {
keyConcat += key
valSum += val
var allGreaterThan25 = every(obj, function (val, key, obj) {
return val > 25
})
keyConcat // = 'foobarbaz'
valSum // = 60
allGreaterThan25 // false
*/
```

## map
## find

Creates a new object with the results of calling a provided function on every value in the object.
Find the value of the the object that passes the test implemented by the callback.

* @param {object} [obj] - object to map values, not accepted if being used directly on Object.prototype
* @param {function} callback - function that produces the new value for the new, mapped object
* @param {*} [thisArg] - optional. context to bind to callback
* @returns {object} newly created object with mapped values
* @param {object} [obj] - object to iterate through, not accepted if being used directly on Object.prototype
* @param {findCallback} callback - function to test each value in the object. return truthy to end the loop and return index, falsey otherwise.
* @param {*} [thisArg] - optional. context to bind to callback
* @returns {*} if callback returns true, the loop is ended and the passing `val` is returned (else undefined)

```js
var map = require('object-loops/map')
var find = require('object-loops/find')

var obj = {
foo: 10,
bar: 20,
baz: 30
baz: 30,
qux: 40,
}
var mappedObj = map(obj, function (val, key, obj) {
return val*2
var key = find(obj, function (val, key, obj) {
return val > 25
})
mappedObj /* Each val multiplied by 2
{
foo: 20,
bar: 40,
baz: 60
key // 30
var notfound = find(obj, function (val, key, obj) {
return val > 100
})
notfound // undefined
*/
```

## findKey

Find the key of the the object that passes the test implemented by the callback. Very similar to `Array.prototype.findIndex`

* @param {object} [obj] - object to iterate through, not accepted if being used directly on Object.prototype
* @param {findKeyCallback} callback - function to test each value in the object. return truthy to end the loop and return index, falsey otherwise.
* @param {*} [thisArg] - optional. context to bind to callback
* @returns {*} if callback returns true, the loop is ended and the passing `key` is returned (else undefined)

```js
var findKey = require('object-loops/find-key')

var obj = {
foo: 10,
bar: 20,
baz: 30,
qux: 40,
}
var key = findKey(obj, function (val, key, obj) {
return val > 25
})
key // 'baz'
var notfound = findKey(obj, function (val, key, obj) {
return val > 100
})
notfound // undefined
*/
```

Expand Down Expand Up @@ -134,55 +175,84 @@ filteredObj /* Only has entries with vals greater than 25
*/
```

## reduce
## forEach

Applies a function against an accumulator and each value of the object to reduce it to a single value.
Executes a provided function once per each object value.

* @param {object} [obj] - object to reduce values, not accepted if being used directly on Object.prototype
* @param {function} callback - function to test each value in the object. return true to keep that entry, false otherwise.
* @param {*} [initialValue] - optional. object to use as the first argument to the first call of the callback
* @returns {*} finalValue - final value returned by reduction, or just first val if only one exists.
* @param {object} [obj] - object to forEach, not accepted if being used directly on Object.prototype
* @param {function} callback - function that will be invoked once for each key-value pair
* @param {*} [thisArg] - optional. context to bind to callback

```js
var reduce = require('object-loops/reduce')
var forEach = require('object-loops/for-each')

var obj = {
foo: 10,
bar: 20,
baz: 30
}
var sum = reduce(obj, function (prevVal, val, key, obj) {
return prevVal + val
var keyConcat = ''
var valSum = 0
forEach(obj, function (val, key, obj) {
keyConcat += key
valSum += val
})
sum // 60
keyConcat // = 'foobarbaz'
valSum // = 60
```

## every
## map

Tests whether every value in the object passes the test implemented by the callback.
Creates a new object with the results of calling a provided function on every value in the object.

* @function module:object-loops/every
* @param {object} [obj] - object to iterate through, not accepted if being used directly on Object.prototype
* @param {everyCallback} callback - function to test each value in the object. return falsey to end the loop, truthy otherwise.
* @param {object} [obj] - object to map values, not accepted if being used directly on Object.prototype
* @param {function} callback - function that produces the new value for the new, mapped object
* @param {*} [thisArg] - optional. context to bind to callback
* @returns {boolean} if callback returns false, the loop is ended and false is returned (else false)
* @returns {object} newly created object with mapped values

```js
var every = require('object-loops/every')
var map = require('object-loops/map')

var obj = {
foo: 10,
bar: 20,
baz: 30,
qux: 40,
baz: 30
}
var allGreaterThan25 = every(obj, function (val, key, obj) {
return val > 25
var mappedObj = map(obj, function (val, key, obj) {
return val*2
})
allGreaterThan25 // false
mappedObj /* Each val multiplied by 2
{
foo: 20,
bar: 40,
baz: 60
}
*/
```

## reduce

Applies a function against an accumulator and each value of the object to reduce it to a single value.

* @param {object} [obj] - object to reduce values, not accepted if being used directly on Object.prototype
* @param {function} callback - function to test each value in the object. return true to keep that entry, false otherwise.
* @param {*} [initialValue] - optional. object to use as the first argument to the first call of the callback
* @returns {*} finalValue - final value returned by reduction, or just first val if only one exists.

```js
var reduce = require('object-loops/reduce')

var obj = {
foo: 10,
bar: 20,
baz: 30
}
var sum = reduce(obj, function (prevVal, val, key, obj) {
return prevVal + val
})
sum // 60
```

## some

Tests whether some value in the object passes the test implemented by the callback.
Expand Down
62 changes: 62 additions & 0 deletions find-key.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* @module object-loops/find-key
*/

var isInteger = require('101/is-integer')

var castArrayKey = function (key) {
var num = parseInt(key, 10)
return isNaN(num) ? key : num
}

/**
* Find the key of the the object that passes the test implemented by the callback.
* @function module:object-loops/find-key
* @param {object} [obj] - object to iterate through, not accepted if being used directly on Object.prototype
* @param {findKeyCallback} callback - function to test each value in the object. return truthy to end the loop and return index, falsey otherwise.
* @param {*} [thisArg] - optional. context to bind to callback
* @returns {*} if callback returns true, the loop is ended and the passing `key` is returned (else undefined)
*/
module.exports = findKey

function findKey (obj, callback, thisArg) {
var isArray = Array.isArray(obj)
if (isArray && obj.findIndex) {
/* $lab:coverage:off$ */ // not covered in envs that don't have `findIndex`
var index = obj.findIndex(callback, thisArg)
return ~index ? index : undefined
/* $lab:coverage:on$ */
}
if (typeof obj !== 'object' && typeof obj !== 'function') {
throw new TypeError(obj + ' must be an object')
}
if (typeof callback !== 'function') {
throw new TypeError(callback + ' must be a function')
}
var ret
var keys = Object.keys(obj)

if (isArray) {
keys = Object.keys(obj).map(castArrayKey).filter(isInteger)
}

for (var i = 0; i < keys.length; i++) {
var key = keys[i]
var val = obj[key]
var pass = callback.call(thisArg, val, key, obj)

if (pass) {
return key
}
}

return ret
}
/**
* This callback type is called `findKeyCallback` and is displayed as a global symbol.
* @callback findKeyCallback
* @param {*} val - value for key
* @param {string} key - object key (used in current iteration)
* @param {object} obj - object which values are being iterated
* @returns {boolean} include - return true to break loop and return key, false otherwise
*/
28 changes: 28 additions & 0 deletions find.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* @module object-loops/find
*/
var findKey = require('./find-key')

/**
* Find the value of the the object that passes the test implemented by the callback.
* @function module:object-loops/find
* @param {object} [obj] - object to iterate through, not accepted if being used directly on Object.prototype
* @param {findCallback} callback - function to test each value in the object. return truthy to end the loop and return index, falsey otherwise.
* @param {*} [thisArg] - optional. context to bind to callback
* @returns {*} if callback returns true, the loop is ended and the passing `val` is returned (else undefined)
*/
module.exports = find

function find (obj, callback, thisArg) {
var key = findKey(obj, callback, thisArg)
return key ? obj[key] : undefined
}

/**
* This callback type is called `findCallback` and is displayed as a global symbol.
* @callback findCallback
* @param {*} val - value for key
* @param {string} key - object key (used in current iteration)
* @param {object} obj - object which values are being iterated
* @returns {boolean} include - return true to break loop and return value, false otherwise
*/
4 changes: 3 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ module.exports = extendObjectPrototype
function extendObjectPrototype (hideWarnings) {
[
'every',
'forEach',
'filter',
'find',
'findKey',
'forEach',
'map',
'mapKeys',
'reduce',
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "object-loops",
"version": "0.5.2",
"description": "Functional methods like forEach, map, filter, and other ES5 Array methods for Objects in javascript",
"description": "Functional methods like forEach, map, filter, and other Array methods for Objects in javascript",
"main": "index.js",
"directories": {
"test": "test"
Expand Down
4 changes: 3 additions & 1 deletion test/fixtures/reset-object-prototype.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
var methodNames = [
'every',
'forEach',
'filter',
'find',
'findKey',
'forEach',
'map',
'mapKeys',
'reduce',
Expand Down
Loading

0 comments on commit a7ef4b7

Please sign in to comment.