Skip to content

Commit 0705bb1

Browse files
feat: add object/inverse
Ref: #8755
1 parent 9446418 commit 0705bb1

10 files changed

Lines changed: 979 additions & 0 deletions

File tree

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
<!--
2+
3+
@license Apache-2.0
4+
5+
Copyright (c) 2018 The Stdlib Authors.
6+
7+
Licensed under the Apache License, Version 2.0 (the "License");
8+
you may not use this file except in compliance with the License.
9+
You may obtain a copy of the License at
10+
11+
http://www.apache.org/licenses/LICENSE-2.0
12+
13+
Unless required by applicable law or agreed to in writing, software
14+
distributed under the License is distributed on an "AS IS" BASIS,
15+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
See the License for the specific language governing permissions and
17+
limitations under the License.
18+
19+
-->
20+
21+
# Object Inverse
22+
23+
> Invert an object, such that keys become values and values become keys.
24+
25+
<section class="usage">
26+
27+
## Usage
28+
29+
```javascript
30+
var invert = require( '@stdlib/object/inverse' );
31+
```
32+
33+
#### invert( obj\[, options] )
34+
35+
Inverts an `object`, such that keys become values and values become keys.
36+
37+
```javascript
38+
var out = invert({
39+
'a': 'beep',
40+
'b': 'boop'
41+
});
42+
// returns { 'beep': 'a', 'boop': 'b' }
43+
```
44+
45+
The function accepts the following `options`:
46+
47+
- **duplicates**: `boolean` indicating whether to store keys mapped to duplicate values in `arrays`. Default: `true`.
48+
49+
By default, keys mapped to duplicate values are stored in `arrays`.
50+
51+
```javascript
52+
var out = invert({
53+
'a': 'beep',
54+
'b': 'beep'
55+
});
56+
// returns { 'beep': [ 'a', 'b' ] }
57+
```
58+
59+
To **not** allow duplicates, set the `duplicates` option to `false`. The output `key-value` pair will be the `key` most recently inserted into the input `object`.
60+
61+
```javascript
62+
var obj = {};
63+
obj.a = 'beep';
64+
obj.b = 'boop';
65+
obj.c = 'beep'; // inserted after `a`
66+
67+
var out = invert( obj, {
68+
'duplicates': false
69+
});
70+
// returns { 'beep': 'c', 'boop': 'b' }
71+
```
72+
73+
</section>
74+
75+
<!-- /.usage -->
76+
77+
<section class="notes">
78+
79+
## Notes
80+
81+
- Beware when providing `objects` having values which are themselves `objects`. This implementation relies on native `object` serialization (`#toString`) when converting values to keys.
82+
83+
```javascript
84+
var obj = {
85+
'a': [ 1, 2, 3 ],
86+
'b': {
87+
'c': 'd'
88+
}
89+
};
90+
91+
var out = invert( obj );
92+
// returns { '1,2,3': 'a', '[object Object]': 'b' }
93+
```
94+
95+
- Insertion order is not guaranteed, as `object` key enumeration is not specified according to the [ECMAScript specification][ecma-262-for-in]. In practice, however, most engines use insertion order to sort an `object`'s keys, thus allowing for deterministic inversion.
96+
97+
</section>
98+
99+
<!-- /.notes -->
100+
101+
<section class="examples">
102+
103+
## Examples
104+
105+
<!-- eslint no-undef: "error" -->
106+
107+
```javascript
108+
var randu = require( '@stdlib/random/base/randu' );
109+
var round = require( '@stdlib/math/base/special/round' );
110+
var invert = require( '@stdlib/object/inverse' );
111+
112+
var keys;
113+
var arr;
114+
var out;
115+
var i;
116+
117+
// Create an array of random integers...
118+
arr = new Array( 1000 );
119+
for ( i = 0; i < arr.length; i++ ) {
120+
arr[ i ] = round( randu()*100.0 );
121+
}
122+
// Invert the array to determine value frequency...
123+
out = invert( arr );
124+
keys = Object.keys( out );
125+
for ( i = 0; i < keys.length; i++ ) {
126+
if ( out[ i ] ) {
127+
out[ i ] = out[ i ].length;
128+
} else {
129+
out[ i ] = 0;
130+
}
131+
}
132+
console.dir( out );
133+
```
134+
135+
</section>
136+
137+
<!-- /.examples -->
138+
139+
<!-- Section for related `stdlib` packages. Do not manually edit this section, as it is automatically populated. -->
140+
141+
<section class="related">
142+
143+
* * *
144+
145+
## See Also
146+
147+
- <span class="package-name">[`@stdlib/utils/object-inverse-by`][@stdlib/utils/object-inverse-by]</span><span class="delimiter">: </span><span class="description">invert an object, such that keys become values and values become keys, according to a transform function.</span>
148+
149+
</section>
150+
151+
<!-- /.related -->
152+
153+
<!-- Section for all links. Make sure to keep an empty line after the `section` element and another before the `/section` close. -->
154+
155+
<section class="links">
156+
157+
[ecma-262-for-in]: https://262.ecma-international.org/5.1/#sec-12.6.4
158+
159+
<!-- <related-links> -->
160+
161+
[@stdlib/utils/object-inverse-by]: https://github.com/stdlib-js/stdlib/tree/develop/lib/node_modules/%40stdlib/utils/object-inverse-by
162+
163+
<!-- </related-links> -->
164+
165+
</section>
166+
167+
<!-- /.links -->
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/**
2+
* @license Apache-2.0
3+
*
4+
* Copyright (c) 2018 The Stdlib Authors.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
'use strict';
20+
21+
// MODULES //
22+
23+
var bench = require( '@stdlib/bench' );
24+
var randu = require( '@stdlib/random/base/randu' );
25+
var pkg = require( './../package.json' ).name;
26+
var invert = require( './../lib' );
27+
28+
29+
// MAIN //
30+
31+
bench( pkg, function benchmark( b ) {
32+
var obj;
33+
var out;
34+
var i;
35+
36+
obj = {
37+
'a': 'beep',
38+
'b': 'boop',
39+
'c': 'foo',
40+
'd': 'bar',
41+
'e': randu()
42+
};
43+
b.tic();
44+
for ( i = 0; i < b.iterations; i++ ) {
45+
obj.e = randu();
46+
out = invert( obj );
47+
if ( typeof out !== 'object' ) {
48+
b.fail( 'should return an object' );
49+
}
50+
}
51+
b.toc();
52+
if ( typeof out !== 'object' ) {
53+
b.fail( 'should return an object' );
54+
}
55+
b.pass( 'benchmark finished' );
56+
b.end();
57+
});
58+
59+
bench( pkg+':duplicates=true', function benchmark( b ) {
60+
var opts;
61+
var obj;
62+
var out;
63+
var i;
64+
65+
obj = {
66+
'a': 'beep',
67+
'b': 'beep',
68+
'c': 'beep',
69+
'd': 'beep',
70+
'e': randu()
71+
};
72+
opts = {
73+
'duplicates': true
74+
};
75+
b.tic();
76+
for ( i = 0; i < b.iterations; i++ ) {
77+
obj.e = randu();
78+
out = invert( obj, opts );
79+
if ( typeof out !== 'object' ) {
80+
b.fail( 'should return an object' );
81+
}
82+
}
83+
b.toc();
84+
if ( typeof out !== 'object' ) {
85+
b.fail( 'should return an object' );
86+
}
87+
b.pass( 'benchmark finished' );
88+
b.end();
89+
});
90+
91+
bench( pkg+':duplicates=false', function benchmark( b ) {
92+
var opts;
93+
var obj;
94+
var out;
95+
var i;
96+
97+
obj = {
98+
'a': 'beep',
99+
'b': 'beep',
100+
'c': 'beep',
101+
'd': 'beep',
102+
'e': randu()
103+
};
104+
opts = {
105+
'duplicates': false
106+
};
107+
b.tic();
108+
for ( i = 0; i < b.iterations; i++ ) {
109+
obj.e = randu();
110+
out = invert( obj, opts );
111+
if ( typeof out !== 'object' ) {
112+
b.fail( 'should return an object' );
113+
}
114+
}
115+
b.toc();
116+
if ( typeof out !== 'object' ) {
117+
b.fail( 'should return an object' );
118+
}
119+
b.pass( 'benchmark finished' );
120+
b.end();
121+
});
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
2+
{{alias}}( obj[, options] )
3+
Inverts an object, such that keys become values and values become keys.
4+
5+
Beware when providing objects having values which are themselves objects.
6+
The function relies on native object serialization (`#toString`) when
7+
converting values to keys.
8+
9+
Insertion order is not guaranteed, as object key enumeration is not
10+
specified according to the ECMAScript specification. In practice, however,
11+
most engines use insertion order to sort an object's keys, thus allowing for
12+
deterministic inversion.
13+
14+
Parameters
15+
----------
16+
obj: ObjectLike
17+
Input object.
18+
19+
options: Object (optional)
20+
Options.
21+
22+
options.duplicates: boolean (optional)
23+
Boolean indicating whether to store keys mapped to duplicate values in
24+
arrays. Default: `true`.
25+
26+
Returns
27+
-------
28+
out: Object
29+
Inverted object.
30+
31+
Examples
32+
--------
33+
// Basic usage:
34+
> var obj = { 'a': 'beep', 'b': 'boop' };
35+
> var out = {{alias}}( obj )
36+
{ 'beep': 'a', 'boop': 'b' }
37+
38+
// Duplicate values:
39+
> obj = { 'a': 'beep', 'b': 'beep' };
40+
> out = {{alias}}( obj )
41+
{ 'beep': [ 'a', 'b' ] }
42+
43+
// Override duplicate values:
44+
> obj = {};
45+
> obj.a = 'beep';
46+
> obj.b = 'boop';
47+
> obj.c = 'beep';
48+
> out = {{alias}}( obj, { 'duplicates': false } )
49+
{ 'beep': 'c', 'boop': 'b' }
50+
51+
See Also
52+
--------
53+

0 commit comments

Comments
 (0)