This is the function I wrote to retrieve all the values in an given object.
function getValues(data){
var keys = Object.keys(data);
var values = [];
for(var i = 0, l = keys.length, key; i< l; i++){
key = keys[i];
values.push(data[key]);
}
return values;
}
Is there any builtin way to retrieve all the values in an object? Something like this exists in java for HashMaps. I know JS has a method for retrieving all the keys by doing Object.keys(obj).
Probably the most concise way of getting an array of the values contained within an object is to use Object.keys and Array.prototype.map:
obj = {
a: 1,
b: 2,
c: 3
};
values = Object.keys(obj).map(function (key) {
return obj[key];
});
Otherwise there's no standardized way of getting an array of an object's values.
For iterating, ES6 introduces a for..of loop which will iterate through an object's values:
continued from above:
for (value of obj) {
console.log(value); //1, 2, 3
}
ES7 is slated to introduce array comprehensions, so generating the values array could be written as:
continued from above:
values = [for (x of Object.keys(obj)) obj[x]];
If you're already using underscore, you can use the _.values method:
continued from above:
_.values(obj); //[1, 2, 3]
If you just want an efficient implementation for this utility function, the lodash source is:
lodash.js v2.4.1 lines 2891-2914
/**
* Creates an array composed of the own enumerable property values of `object`.
*
* #static
* #memberOf _
* #category Objects
* #param {Object} object The object to inspect.
* #returns {Array} Returns an array of property values.
* #example
*
* _.values({ 'one': 1, 'two': 2, 'three': 3 });
* // => [1, 2, 3] (property order is not guaranteed across environments)
*/
function values(object) {
var index = -1,
props = keys(object),
length = props.length,
result = Array(length);
while (++index < length) {
result[index] = object[props[index]];
}
return result;
}
You could do this, in newer Browsers:
Object.defineProperty(Object.prototype, 'values', {
get:function(){
return function(o){
var a = [];
for(var i in o){
a.push(o[i]);
}
return a;
}
}
});
var arrayOfValues = Object.values({a:'A',b:'B',c:'C'});
Really, I would just do:
function objectValues(obj, inherited){
var a = [];
for(var i in obj){
var v = obj[i];
if(inherited){
a.push(v);
}
else if(obj.hasOwnProperty(i)){
a.push(v);
}
}
return a;
}
var notInheritedArrayOfValues = objectValues({a:'A',b:'B',c:'C'});
var inheritedArrayOfValues = objectValues({a:'A',b:'B',c:'C'}, true);
Related
I would like to create an object containing all the values from the array first and the values from second as an array of values, assuming that this key references multiple numbers such that given the arrays:
first = [3,0,5,3]
second = [1,3,10,5]
my output would be {0: 3, 3: [1,5], 5: 10}
This is what I have tried:
const newObj = {}
for(let i = 0; i < first.length; i++){
newObj[first[i]] = second[i] ? [ second[i] ] : second[i]
}
This is what I get:
{ '0': [ 3 ], '3': [ 5 ], '5': [ 10 ] }
This is the easiest method to understand as it's just the bare logic written in its entirety.
for (let i = 0; i < first.length; i++) {
if (first[i] in newObj) { // If key exists already
if (typeof newObj[first[i]] === "number") { // and if it's a number
newObj[first[i]] = [newObj[first[i]]]; // then we wrap it into an array
}
newObj[first[i]].push(second[i]); // add the new number
} else {
newObj[first[i]] = second[i]; // if it doesn't exist then add it
}
}
You can loop through all the items. You have three conditions for every array element you get. You will try to map it to a key of your new object you are creating and these will be the cases:
the key exists and value is already an array. (just push to the value)
the key exists and is not an array. (just create an array of two values)
the key does not exist. (just add a new key value pair)
const first = [3,0,5,3];
const second = [1,3,10,5];
const ans = {};
first.forEach((curr,index) => {
if(Array.isArray(ans[curr])){ ans[curr] = [...ans[curr],second[index]];
}
else{
if(ans[curr]){ans[curr] = [ans[curr],second[index]];
}
else ans[curr] = second[index];
}
});
console.log(ans);
I would collect all the values into arrays, regardless of how many there are (the transform function below does this) — having a data structure with uniform types is more predictable/easier to work with.
Then, in a subsequent step, the single element from the arrays with only one element can be extracted (the extractSingleArrayElements function below does this). See comments in the code for explanation:
Code in TypeScript Playground
'use strict';
/**
* Takes an array of keys and an array of values, and returns an object
* with values collected in arrays grouped by the keys that match their indexes
*
* #param {number[]} keys Array of integer keys
* #param {number[]} values Array of integer values
* #returns {Record<string, number[]>}
*/
function transform (keys, values) {
// Ensure that the lengths of the arrays are the same before proceeding:
if (keys.length !== values.length) throw new Error('Input lengths differ');
const result = {};
for (let i = 0; i < values.length; i += 1) {
const key = keys[i];
const value = values[i];
// Create a refrence to the array of values at the key,
// first creating and assigning it to the object at the key
// if it doesn't already exist:
const array = (result[key] ??= []);
array.push(value);
}
return result;
}
/**
* Takes an object with array values and returns a shallow copy of the object,
* replacing any array values that have only one element with the element itself
*
* #param {Record<string, number[]>} obj
* #returns {Record<string, number | number[]>}
*/
function extractSingleArrayElements (obj) {
const result = {};
for (const [key, array] of Object.entries(obj)) {
result[key] = array.length === 1 ? array[0] : array;
}
return result;
}
const keys = [3, 0, 5, 3];
const values = [1, 3, 10, 5];
const transformed = transform(keys, values);
const actual = extractSingleArrayElements(transformed);
const expected = {0: 3, 3: [1, 5], 5: 10};
console.log(JSON.stringify(actual) === JSON.stringify(expected)); // true
This is my suggestion for it, using Array.reduce, spread syntax and computed property names
first.reduce((o, k, i) => ({ ...o, [k]: [...o[k]||[], second[i]] }), {})
first = [3,0,5,3]
second = [1,3,10,5]
output = first.reduce((o, k, i) => ({ ...o, [k]: [...o[k]||[], second[i]] }), {})
console.log(output)
You can find detailed explanation on this strategy in this other answer.
I want to double the key values in an array of objects and I always end up getting the last key:val in the list. I want to be able to print the whole array of objects doubled their values.
doubleArr = [];
function doubleSize (a,b) {
for(var i in a) {
if (a.hasOwnProperty(i)) {
var doubleObj = {};
doubleObj[i] = b * a[i];
var results = doubleObj[i];
doubleArr.push(results);
}
}
return doubleObj;
}
console.log(doubleSize({1:1,1:2,1:3,1:4,1:5}, 2))
I only get {1:10}. The goal is to get {1:2,1:4,1:6,1:8,1:10}. Thanks.
The primary issue with your code is that you cannot have duplicate keys in an object. Every key in an object must be unique; otherwise, you are essentially redeclaring the value associated with that key over and over (so, naturally, in your example, the key 1 will end up being associated with the last value you assign it: 5).
However, even if you used an object without duplicate keys, you still have the following issues:
Your doubleArr should not be declared in the global scope, but instead within the function; moreover, you don't need an array for what you're doing
Your code is actually constructing an array of objects rather than an object. If you want to return an object, you should build up an object with unique values in your function.
Here's an example of a modified version of your code:
function doubleSize (a,b) {
var doubleObj = {};
for(var i in a) {
if (a.hasOwnProperty(i)) {
doubleObj[i] = b * a[i];
}
}
return doubleObj;
}
console.log(doubleSize({1:1,2:2,3:3,4:4,5:5}, 2)) // Note the unique keys
However, I don't fully understand the need for objects. You could use arrays instead, and then replace all of your code with a simple one-liner using Array.map:
var arr = [1, 2, 3, 4, 5]
var doubledArr = arr.map(x => 2*x) // An arrow function that multiplies each value in the array by 2
console.log(doubledArr)
You are using the same key for your objects 1. I am assuming that you don't need objects as they don't provide anything obvious to your code:
Edit If you insist on using objects, I have provided the second version also.
function doubleSize (a,b)
{
var doubleArr = [];
for(var i=0; i<a.length;i++)
{
doubleArr.push(a[i]*b);
}
return doubleArr;
}
console.log(doubleSize([1,2,3,4,5], 2))
function doubleSize2 (a,b)
{
var result = {};
for(var i in a)
{
result[i] = a[i]*b
}
return result;
}
console.log(doubleSize2({a:1,b:2,c:3,d:4,e:5}, 2))
You can't have duplicate keys in an object, you can have an array of objects with the same key though. Something like:
function doubleSize (a, b) {
var out = [];
for(var i = 0; i < a.length; i++) {
out.push({'1': a[i]['1'] * b});
}
return out;
}
console.log(doubleSize([{'1': 1}, {'1': 2}, {'1': 3}, {'1': 4}, {'1': 5}], 2));
function doubleSize (a,b) {
var midObject = {};
for(var i in a) {
if (a.hasOwnProperty(i)) {
midObject[i] = b * a[i];
}
}
return midObject;
}
console.log(doubleSize({1:1,2:2,3:3,4:4,5:5}, 5))
I want extend javascript Array to implement map2 functionality without using inbuilt map function. Where map2 functionality doubles the passed value of the array.
For example:
var m = [1,2,3,4,5]
var double = [1,2,3,4,5].map2(doubleFn)
console.log(double) should output 2,4,6,8,10
And above functionality need be developed by without using any in built method of JS array
Code Snippet
Array.prototype.map2= function(callback, thisArg){
var len=this.length
for(var i in this){
callback.call(this,this[i]*2)
}
}
Please let me know, what approach can I follow to do this
Array.prototype.map2 = function (callback, thisArg){
var i, el,
len = this.length,
res = [],
_this = thisArg ? thisArg : this;
for (i = 0; i < len; i++) {
el = this[i]; // also you can use this[i] * 2 - it depend what do want;
res[i] = callback.call(_this, el);
}
return res;
};
var double = [1,2,3,4,5].map2(function (el) {
return el * 2;
});
Example
About you errors, don't use for..in for Arrays., in map you need create new array and return it...
I'm guessing that you want to re implement built in Array.prototype.map.
Here's one of the way of doing it:
Array.prototype.map2 = function(f1){
var a = [];
this.forEach(function(element){
a.push(f1(element));
})
return a;
}
a = [1,2,3,4,5]
console.log(a.map2(function(a){return a<<1;});
//output: [ 2, 4, 6, 8, 10 ]
Edit: without using inbuilt functions:
Array.prototype.map2 = function(f1){
var a = [];
var that = this;
return (function recArray(index, target){
if(typeof(that[index]) !== 'undefined') {
target[index] = f1(that[index]);
return recArray(index + 1, target);
}
return target;
})(0, a);
}
But there is a problem with this solution:
What if input Array has holes:
a = [1,2,3,4,5]
a[12] = 11
//now a is: [ 1, 2, 3, 4, 5, , , , , , , , 11 ]
JavaScript Arrays can have holes and if there are undefined values in between then above method will fail. Without knowing the length of the Array, it is impossible to traverse it if it contains 'holes'.
Explicitly storing length doesn't makes sense as it is stored in Array.prototype.length.
Hence if the array is not contiguous then without using length it is impossible to implement map.
I have a data dictionary like this:
var data = {
'text1': 1,
'text2': 2,
'text3': 3,
...
'text20': 20
];
I need to pick a random selection of those keys and then shuffle it's values. In the example, it should write something like this:
> console.log(choose(data, 5));
[ { key: 'text15', value: 8 },
{ key: 'text6', value: 3 },
{ key: 'text3', value: 15 },
{ key: 'text19', value: 6 },
{ key: 'text8', value: 19 } ]
For now I'm extracting the keys into another array and sorting by Math.random() but I'm stuck at swaping the values because no key should have the same value it initially had.
How would you swap key/values here?
Thanks
I put together a possible solution using underscore.js to simplify traversing the object and arrays in a cross browser manner:
var data = {
text1: 1,
text2: 2,
text3: 3,
text4: 4,
text5: 5,
text6: 6,
text7: 7,
text8: 8,
text9: 9,
text10: 10
};
function choose(data, num)
{
var keys = _.sortBy(
_.keys(data),
function(k)
{
return (Math.random() * 3) - 1;
}
),
results = [],
k1, k2;
if (num > keys.length) {
throw new Error('Impossible to retrieve more values than exist');
}
while (results.length < num) {
k1 = k2 || keys.pop();
k2 = keys.pop();
results.push({key:k1, value: data[k2]});
}
return results;
}
console.log(choose(data, 5));
This isn't necessarily an optimal approach but it seems to meet your requirements. I first grab all of the keys and sort them randomly. I then loop through the random keys creating a new object with one key and the following keys value. That way you'll always end up with a different value associated with each key. If you need it to work when the value of num passed in to the function == the number of keys in the data then you'll have to add a little more code - I'll leave that as an exercise for the reader :)
You can have a play with this code on jsfiddle:
http://jsfiddle.net/zVyQW/1/
You could do this:
collect names and corresponding values in two arrays names and values
shuffle both arrays independently of each other
take the first n items of both arrays and combine them
Here’s an example implementation:
Array.prototype.shuffle = function() {
for (var i=this.length-1, j, tmp; i>0; i--) {
j = Math.round(Math.random()*i);
tmp = this[i], this[i] = this[j], this[j] = tmp;
}
return this;
};
function choose(data, number) {
var names = [], values = [], pick = [];
for (var name in data) {
if (data.hasOwnProperty(name)) {
names.push(name);
values.push(data[name]);
}
}
names = names.shuffle(), values = values.shuffle();
for (var i=Math.min(number >>> 0, names.length-1); i>=0; i--) {
pick.push({key: names[i], value: values[i]});
}
return pick;
}
Been a while since this was answered, but I was working on shuffling and found the following to be by far the fastest implementation with an evenly random distribution.
It's fast because it only makes one call to Math.random on each iteration, all the rest is done by property access. It doesn't modify the array, just reassigns values.
function shuffle(a) {
var t, j, i=a.length, rand=Math.random;
// For each element in the array, swap it with a random
// element (which might be itself)
while (i--) {
k = rand()*(i+1)|0;
t = a[k];
a[k]=a[i];
a[i]=t;
}
return a;
}
It uses a combination of three functions (including the Array shuffle prototype method).
Here is the complete code:
var obj = {
"red":"RED",
"blue":"BLUE",
"green":"GREEN",
"yellow":"YELLOW",
"purple":"PURPLE"
};
Array.prototype.shuffle = function(){
for (var i = 0; i < this.length; i++){
var a = this[i];
var b = Math.floor(Math.random() * this.length);
this[i] = this[b];
this[b] = a;
}
}
obj = shuffleProperties(obj); // run shuffle
function shuffleProperties(obj) {
var new_obj = {};
var keys = getKeys(obj);
keys.shuffle();
for (var key in keys){
if (key == "shuffle") continue; // skip our prototype method
new_obj[keys[key]] = obj[keys[key]];
}
return new_obj;
}
function getKeys(obj){
var arr = new Array();
for (var key in obj)
arr.push(key);
return arr;
}
for(key in obj){
alert(key);
}
Check all post,
Best Regards.
Use an implementation of random that randomizes a discrete set of values, such as Math.rand seen here. For each index, randomize Math.rand(index, length-1) to get a list of random indexes, the location off all indices will change.
status_name=Array("a","b","c","b","e","f");
status_id=Array( 1, 2, 3, 4, 5, 6);
How to combine these two arrays and to built multi dimensional array Expected Multidimensional array be like this
[["a", 1],["b", 2],["c", 3],["d", 4],["e", 5],["f", 6]]
Help me how to use above two array values and built my expected multidimensional array
Since you're including jQuery, you can use jQuery.map in a similar fashion to Linus' answer:
var result = [],
status_name = ["a","b","c","b","e","f"],
status_id = [1, 2, 3, 4, 5, 6];
result = $.map(status_name, function (el, idx) {
return [[el, status_id[idx]]];
});
Looking at your variable names, I'd guess that your coming from a language (like PHP). If that's the case, make sure you remember to declare local variables with the var keyword, otherwise you'll be polluting the global scope and you'll run into some hideous bugs in IE.
JavaScript has no buitin method for this, but you can easily write it yourself:
function zip(arrayA, arrayB) {
var length = Math.min(arrayA.length, arrayB.length);
var result = [];
for (var n = 0; n < length; n++) {
result.push([arrayA[n], arrayB[n]]);
}
return result;
}
The name zip is chosen because a function that does something like this is often called zip in other languages.
I tried Myself and brought this solution, It might help some one
status_name=Array("a","b","c","b","e","f");
status_id=Array( 1, 2, 3, 4, 5, 6);
Script:
Values=[];
for (i = 0; i < status_name.length; ++i)
{
Values[i] =Array(status_name[i], status_id[i]);
}
Using jQuery.map
var status_name = ["a","b","c","b","e","f"],
status_id = [1,2,3,4,5,6],
r = [];
r = $.map(status_name, function(n, i) {
return [[n, status_id[i]]];
});
Note the difference between return [[n, status_id[i]]] and return [n, status_id[i]]. Using the former will result in a 2d array while using the latter will result in a 1d array.
var combined = [], length = Math.min(status_name.length, status_id.length);
for(var i = 0; i < length; i++) {
combined.push([status_name[i], status_id[i]]);
}
You could also use Array.prototype.map, but that's not supported in all browsers:
var combined = status_name.map(function(name, index) { return [name, status_id[index]] });
try
function array_combine (keys, values) {
// Creates an array by using the elements of the first parameter as keys and the elements of the second as the corresponding values
//
// version: 1102.614
// discuss at: http://phpjs.org/functions/array_combine
// + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + improved by: Brett Zamir (http://brett-zamir.me)
// * example 1: array_combine([0,1,2], ['kevin','van','zonneveld']);
// * returns 1: {0: 'kevin', 1: 'van', 2: 'zonneveld'}
var new_array = {},
keycount = keys && keys.length,
i = 0;
// input sanitation
if (typeof keys !== 'object' || typeof values !== 'object' || // Only accept arrays or array-like objects
typeof keycount !== 'number' || typeof values.length !== 'number' || !keycount) { // Require arrays to have a count
return false;
}
// number of elements does not match
if (keycount != values.length) {
return false;
}
for (i = 0; i < keycount; i++) {
new_array[keys[i]] = values[i];
}
return new_array;
Reference
- arr combine
- array combine