Javascript 'property inheritance' - javascript

Is there a way to specify common elements for object literals in an array?
For example:
var array = [ {key: "hi", label: "Hi", formatter:deleteCheckboxFormatter},
{key: "hello", label: "Hello", formatter:deleteCheckboxFormatter},
{key: "wut", label: "What?", formatter:deleteCheckboxFormatter}];
All three records use the same formatter. How would you refactor this?

A pair of alternatives come to my mind:
A helper function with the default value for the common field:
function make(key, label) {
return {'key': key, 'label': label, formatter:deleteCheckboxFormatter};
}
var array = [ make("hi", "Hi"),
make("hello", "Hello"),
make("wut", "What?")];
Or a more generic function that accepts an argument for the formatter property:
function make (formatter) {
return function (key, label) {
return {'key': key, 'label': label, 'formatter':formatter};
}
}
// a function to build objects that will have a 'fooFormatter'
var foo = make('fooFormatter');
var array = [ foo ("hi", "Hi"),
foo ("hello", "Hello"),
foo ("wut", "What?")];
And the last thing that comes to my mind is simply iterate over the array assigning the common field:
var array = [ {key: "hi", label: "Hi"},
{key: "hello", label: "Hello"},
{key: "wut", label: "What?"}];
var i = array.length;
while (i--) {
array[i].formatter = 'deleteCheckboxFormatter';
}
I used here a while loop in reverse order, because the order of iteration is not important and this type of loop performs better.

var array = [ {key: "hi", label: "Hi"},
{key: "hello", label: "Hello"},
{key: "wut", label: "What?"}];
for(var item in array)
item["formatter"] = deleteCheckboxFormatter;

You could make an object out of it using a constructor:
function Obj(key, label){
this.key = key;
this.label = label;
this.formatter = "deleteCheckboxFormatter";
}
var array = [ new Obj("hi", "Hi"),
new Obj("hello", "Hello"),
new Obj("wut", "What?") ];

Related

Dynamically add a property with spread operator

Let's take 2 objects and let's say I want to dynamically add a key to the first object with the value of the second, and to do this I want to use the spread operator.
let object1 = { key: 'myKey1', value:1 };
let object2 = { field: 'key', displaValue:'chiave' };
something like this:
let object3 = {...object1, [object2.displayValue)]: object1[object2.field] }
But unfortunately I have this result with the undefined key:
{key: "myKey1", value: 1, undefined: "myKey1"}
Expected result:
{key: "myKey1", value: 1, chiave: "myKey1"}

Change the nested array object by passing parameter in javascript

I would like to know how to change particular field by passing parameter type in javascript
I have object obj1, obj2, if the parameter type is string/array change the value field
as shown in expected output and vice-versa
function ChangeObj(obj, str){
var result = obj.map(e=> str==="string" ? ({...e, value:[e.value]}) : ({...e,value: e.value.toString()}) )
return result;
}
var obj1 =[
{ key: "country", id:0, value: "SG"},
{ key: "city", id:1, value: "IN"}
]
var obj2 = [
{ key: "cn", id:0, value: ["TH","MY"],img:"sample.jpg"},
{ key: "list", id:1, value: ["AU"], img:"item.jpg" }
]
var output1 = this.ChangeObj(obj1, "array");
var output2 = this.ChangeObj(obj2, "string");
Expected Output:
//output 1
[
{ key: "country", id:0, value: ["SG"] },
{ key: "city", id:1, value: ["IN"] }
]
// output 2
[
{ key: "cn", id:0, value: "TH", img:"sample.jpg"},
{ key: "cn", id:0, value: "MY", img:"sample.jpg" },
{ key: "list", id:1, value: "AU", img:"item.jpg" }
]
Because you want to generate multiple values when converting an array to a string, you can't use map directly. Instead, you could use reduce and then map the object value property inside the reduce:
function ChangeObj(obj, str) {
var result = obj.reduce((c, o) => c.concat(str === "array" ? [{ ...o,
value: [o.value]
}] : o.value.map(v => ({ ...o,
value: v
}))), []);
return result;
}
var obj1 =[
{ key: "country", id:0, value: "SG"},
{ key: "city", id:1, value: "IN"}
]
var obj2 = [
{ key: "cn", id:0, value: ["TH","MY"],img:"sample.jpg"},
{ key: "list", id:1, value: ["AU"], img:"item.jpg" }
]
var output1 = this.ChangeObj(obj1, "array");
var output2 = this.ChangeObj(obj2, "string");
console.log(output1);
console.log(output2);
Note that the sense of your ternary conditional is wrong and I have corrected it to str === "array" in this code.
Two issues:
You reversed the cases of string/array: in first case you want to wrap strings in arrays, but you pass "array" as second argument, while the function performs this wrapping when that argument is "string". So either you pass the wrong argument, or else the ternary expression should have the opposite condition.
When converting array to string you are currently applying toString to the array. But that will not multiply the number of objects in the output. It will just produce a comma separated string in one single object.
You can still use map to solve that last issue, but then apply a .flat to resolve the nested array that you'll get:
obj.map(e => str !== "string"
? {...e, value: [e.value]}
: e.value.map(value => ({...e,value}) )
).flat();

Fast way to flatten an array of objects in Javascript

I have an array of generated objects like the following:
[
{obj1: {
key: 'value'
}},
{obj2: {
key: 'value2'
}},
{obj3: {
key: 'value3'
}}
]
I would like to flatten the array, with the following output:
[
{
key: 'value'
},
{
key: 'value2'
},
{
key: 'value3'
}
]
I am doing this with a for loop, which works, but the array will be quite large in size and wonder if there is a more efficient way to do this?
for (var key in array) {
let obj = array[key];
for (var key in obj) {
newArray.push(obj[key]);
}
}
output:
newArray: [
{
key: 'value'
},
{
key: 'value2'
},
{
key: 'value3'
}
]
I'm looking for the simplest method, ES6 or Lodash also welcome for solutions.
Updated to reflect correct array format.
You can simply use reduce and Object.values
let arr = [{obj1: {key: `value`}},{obj2: {key: `value2`
}},{obj3: {key: `value3`}}]
let op = arr.reduce((op,e)=> op.concat(Object.values(e)),[])
console.log(op)
You can use simple for loop when you care about speed.
let arr = [{obj1: {key: `value`}},{obj2: {key: `value2`
}},{obj3: {key: `value3`}}]
let op = []
for(let i=0; i<arr.length; i++){
let values = Object.values(arr[i])
op = op.concat(values)
}
console.log(op)
You can use Array.map, and Object.values.
Map "maps" each element in an array to a new array.
It takes each element of an array, and performs an operation on it.
The result of this operation becomes the corresponding element in a new Array.
This new Array is what's returned.
To convert Objects into Arrays: you can use Object.values, Object.keys, and Object.entries.
Object.values de-references each key in an object, and turns it into an array element holding that key's value.
const arr = [
{obj1: {key: 'value'}},
{obj2: {key: 'value2'}},
{obj3: {key: 'value3'}}
];
let newArr = arr.map(obj => (
{key: Object.values(obj)[0].key}
));
console.log(newArr);
To return an object, it must be wrapped in parenthesis.
In the first iteration, obj == { obj1: { key: 'value' }}, the first element in the input Array, arr.
And,
Object.values(obj) == [{key: 'value'}]
So, we need to grab the element at index 0 to pull the object out of the array {key: 'value'}.
Alternatively, if you know you can rely on the naming structure of the elements in your array (the outer object's key), you could do this, which may be easier to reason about:
const arr = [
{obj1: {key: 'value'}},
{obj2: {key: 'value2'}},
{obj3: {key: 'value3'}}
];
let newArr2 = arr.map( (obj, i) => (
{ key: obj['obj'+(i+1)].key }
));
console.log(newArr2);
Note: you'll need to wrap the i+1 in parenthesis, to force addition to take precedence over JS auto type conversion and string concatenation. Otherwise instead of obj1, obj2, obj3, you'll get obj01, obj11, obj21 as the object keys.

javascript: truncate object properties in an array

I have an array of objects, say the object looks like following:
var row = {
data: 'test',
text: 'test'
};
I want to loop through the array and just get the object with text property.
What is the best way to do it?
So, I want to loop and the object should look like: row = {text: 'test'}
I tried something like below without luck:
arr.forEach(function (item){ //arr is the array of object
return {text: item.text};
});
Use Array.prototype.map for that:
var arr = [{
data: 'testData',
text: 'testText'
}];
var newArr = arr.map(function(item){
return {text: item.data};
});
The result will look like:
[{ text: 'testData' }]
If you want it to be [ {testText: 'testData' }] then:
var arr = [{
data: 'testData',
text: 'testText'
}];
var newArr = arr.map(function(item){
var obj = {};
obj[item.text] = item.data;
return obj;
});
As you want a object with single key value pair, you don't need to store in object form. You can save them as an array.
var array = [
{
text : "text",
data : "data"
},
{
text : "text1",
data : "data1"
}
]
var newArray = array.map(function(item){
return item.data;
});
your output will look like
['text','text1']

Flattening a list of object properties

I'm finding it difficult to write this code in a functional style after years of working with an imperative mindset.
Given an input like:
[{'id': 'foo', frames: ['bar', 'baz']}, {'id': 'two', frames: ['three', 'four']}]
The output should be:
[ { foo: 'bar' }, { foo: 'baz' }, { two: 'three' }, { two: 'four' } ]
How would one write this in a functional style in javascript?
First let's create a function which given an object returns an array of frames:
function toFrames(obj) {
var id = obj.id;
return obj.frames.map(function (frame) {
var obj = {};
obj[id] = frame;
return obj;
});
}
Next we create a concat function:
function concat(a, b) {
return a.concat(b);
}
Finally we do the transformation:
var input = [{
id: "foo",
frames: ["bar", "baz"]
}, {
id: "two",
frames: ["three", "four"]
}];
var output = input.map(toFrames).reduce(concat);
See the demo for yourself:
var input = [{
id: "foo",
frames: ["bar", "baz"]
}, {
id: "two",
frames: ["three", "four"]
}];
var output = input.map(toFrames).reduce(concat);
alert(JSON.stringify(output, null, 4));
function toFrames(obj) {
var id = obj.id;
return obj.frames.map(function (frame) {
var obj = {};
obj[id] = frame;
return obj;
});
}
function concat(a, b) {
return a.concat(b);
}
Isn't functional programming fun?
An explanation:
The toFrames function takes a object (for example { id: "foo", frames: ["bar", "baz"] }) and returns the list of frame objects (i.e. [{ foo: "bar" }, { foo: "baz" }]).
The concat function just concatenates two arrays. The .reduce(concat) method call flatttens arrays like [[a,b],[c,d]] to [a,b,c,d].
Given an input list of objects, we first convert each object into a list of frames, resulting in a list of list of frame objects.
We then flatten the nested list to produce the desired output.
Simple.
You can do it this way supposing arr is the input
result = []; // array
arr.forEach(function(o) { // go through elements
for (var i = 0; i < o.frames.length; i++) { // make a since we need to get two objs per element
var obj = {}; // an object which will be over written for every iteration
obj[o.id] = o.frames[i]; // set property name and value
result.push(obj); // finally push it in the array
}
});

Categories

Resources