How to convert a object array into string in JavaScript? - javascript

The array is this:
[{name:'name1',id:'id1',val:'001},
...
{name:'name10',id:'id10',val:'010}]
We want to store in the database as a long text string:
name1,id1,001;...;name10,id10,010
values separated by semicolon and comma.
Is there any convenient join or something else to achieve it? (I guess there must be something better than for loop.)

function joinValues(arr, j1, j2) {
return arr.map(function(o) {
return Object.keys(o).map(function(k) {
return o[k];
}).join(j1)
}).join(j2);
}
var obj = [{a:1,b:2},{a:'x',b:'y'}];
joinValues(obj, ',', ';'); // => "1,2;x,y"

array.map(function(o){
var values = Object.keys(o).map(function(key){
return o[key];
});
return values.join(',');
}).reduce(function(a,b){
return a + ';' + b;
});
Beware there might be compat issues depending on your platform (map, reduce, Object.keys not available everywhere yet!)
Also, take into account that properties order in regular objects is not guaranteed. With this approach, theoretically you could end up having name1,id1,001;...;id10,name10,010. That might be an issue when mapping the string back to objects.

I'm afraid there isn't a built-in language feature for that, but if you can use ES6, it can look quite elegant
Object.values = obj => Object.keys(obj).map(key => obj[key]);
// so to convert your data
data.map(o => Object.values(o).join(',')).join(';');

Related

Javascript comparing at least one identical pairs in an object

I have two dictionaries (object in JS?), and I want to compare them.
In a while loop, I want to print True if at least one of the pairs is identical (i.e. the dictionary below), as opposed to the whole dictionary being identical (but if the whole dict is identical the statement must still be True obviously):
my_dict = {"Text1":"Text1", "Text2":"Text3", "text5":"text5"}
I know in python it would be like that:
while any(key == value for key, value in my_dict.items()):
...
else:
...
But I can’t get my hands on the correct syntax for JavaScript.
With Object.entries() and some() this is a one-liner:
let my_dict = {"Text1":"Text1", "Text2":"Text3", "text5":"text5"}
let answer = Object.entries(my_dict).some(([key,value]) => key == value);
console.log(answer)
for(var key in obj){
if(key === obj[key]){
//Do Something
} else {
//Do Something Else
}
}
That iterates through the object, and if the key is equal to the value, then it does something, otherwise it does something else.
You can use the some() function on JavaScript arrays which is identical to any from Python I think.
let my_dict = {"Text1":"Text1", "Text2":"Text3", "text5":"text5"}
let same_exists = Object.keys(my_dict).some((key) => key === my_dict[key])
console.log(same_exists)

Object.entries() alternative for Internet Explorer and ReactJS

Well, I've been building a web application for a couple weeks now, and everything good. I got to the part that I had to test in Internet Explorer, and of all of the things that came up (all fixed except for one), Object.entries() is not supported.
I've been doing some research and try to come up with a simple alternative, but no luck at all.
To be more specific, I'm bringing an object from an API, to fill options for <select></select> fields I have to filter some information, just like this:
Object.entries(this.state.filterInfo.sectorId).map(this.eachOption)
// Function
eachOption = ([key, val], i) => {
return(
<option value={val} key={i}>{val}</option>
);
}
So everything works correctly except for Internet Explorer. The thing is that in this particular component I'm rendering over 30 <select></select> fields. IF there is a solution that doesn't require me to rebuild everything, it would be amazing.
Is there a simple solution? A way around this?
Thanks in advance.
The usual first item to research when you want to use a newer API in an older browser is whether there is a simple polyfill. And, sure enough there is a pretty simple polyfill for Object.entries() shown on the MDN doc site:
if (!Object.entries)
Object.entries = function( obj ){
var ownProps = Object.keys( obj ),
i = ownProps.length,
resArray = new Array(i); // preallocate the Array
while (i--)
resArray[i] = [ownProps[i], obj[ownProps[i]]];
return resArray;
};
Nothing necessarily new to the above answer, but just different code to accomplish the same thing.
Hopefully this helps anyone who stumbles upon this.
// Another approach
const entriesPolyFill = (obj) => Object.keys(obj).map(key => [key, obj[key]]);
// Same thing but easier to read
function entriesPolyFill(obj) {
const keys = Object.keys(obj);
const keyValuePairs = keys.map(key => {
const value = obj[key];
return [key, value];
});
return keyValuePairs;
};
// Possible usage if you don't want to alter Object class:
// Ex: Need key-value pairs to iterate over
const entries = (Object.entries ? Object.entries(obj) : entriesPolyFill(obj));
// Then do whatever you want with the Array
// ---> entries.map(), entries.filter(), etc..
// You could also move the whole thing to a function
// and always call the function so you don't have to
// write excess ternary operators in your code:
// -- In a utils file somewhere else...
export function getEntries(obj) {
return Object.entries ? Object.entries(obj) : Object.keys(obj).map(key => [key, obj[key]]);
}
// Wherever you need to get entries in you project
import { getEntries } from "<path to utils>";
...
const entries = getEntries(obj);
import 'core-js/es7/object';
This works for me.
Here's a concise polyfill using Array.prototype.reduce in a rather clever way:
if(!Object.entries)
Object.entries = function(obj) {
return Object.keys(obj).reduce(function(arr, key) {
arr.push([key, obj[key]]);
return arr;
}, []);
}
Use shim/polyfill like this one: https://github.com/es-shims/Object.entries

JS / ES6: Object to Array conversion

One of my node js libraries is returning some data I need in the wrong format like this:
{"a":["1","2"],"b":["3","4"],"c":["5","6"]}
(note that the values don't matter)
but I need to loop this array in a way, that I find my B for my A that has a certain value (in this case e.g. '2', I would need '4') and all other parts of my program are so far using arrays like this:
[{"a":"1", "b":"3", "c":"5"}, {"a":"2", "b":"4", "c":"6"}]
and it would be my preferred approach.
Also note that the amount of data in a is always the same as b and c, but itself is variable.
So what would be the "best" way to accomplish this in ES6/JS (before I start messing with for-loops)?
If you are looking to transform an object like
{"a":["1","2"],"b":["3","4"],"c":["5","6"]}
Into a array like
[{"a":"1","b":"3","c":"5"},{"a":"2","b":"4","c":"6"}]
Something like this is the simplest way I can think of
function formatData (data) {
return Object.keys(data).reduce((arr, key) => {
data[key].forEach((value, i) => {
const iObj = arr[i] || (arr[i] = {});
iObj[key] = value;
});
return arr;
}, []);
}

JS: Array.map don't add to array

I have some data I'd like to transform using Array.prototype.map. However in the map function there is a chance of an error being thrown by an external function call. I'd like to catch this error and not add that particular object to the returned array. Currently I'm just returning undefined and then using Array.prototype.filter to clear out the undefined values, but this seems like a dirty way to do it.
To clarify, I'm looking for this functionality:
['apple','pear','banana', 'peach'].map(function(fruit){
if (fruit === 'apple') {
return undefined;
}
return 'I love to eat ' + fruit;
});
// ['I love to eat pear', 'I love to eat peach', 'I love to eat banana']
Any existing implementatons of this? Am I just going about this the wrong way?
A more readable way would be;
['apple','pear','banana', 'peach'].filter(function(fruit) {
return fruit === 'apple';
}).map(function(fruit) {
return 'I love eating ' + fruit;
})
With arrow functions & template strings;
['apple','pear','banana', 'peach']
.filter(fruit => fruit === 'apple')
.map(fruit => `I love eating ${fruit}`)
If you don't want to use simple for loop, then instead of map try to use reduce this way:
var result = ['apple','pear','banana', 'peach'].reduce(function(prev, curr){
if (curr === 'apple') {
return prev;
}
prev.push(curr);
return prev;
}, []);
alert(result);
So the idea is that in case of "exception" you simply return prev array without modifying it.
I ended up merging the two methods together into one on the Array prototype. As #Benmj mentioned, you could alternatively put this in a custom utility lib.
Array.prototype.mapDefinedValues = function(handler) {
return this.map(function(item){
return handler(item);
}).filter(function(item){
return item !== undefined;
});
}
Mozilla's MDN for Array.prototype.map() says to use forEach or for-of for that:
Since map builds a new array, using it when you aren't using the returned array is an
anti-pattern; use forEach or for-of instead.
You shouldn't be using map if:
you're not using the array it returns; and/or
you're not returning a value from the callback.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map#When_not_to_use_map
As was stated in the comments, you should combine this with a filter. Luckily, this is easy because you can chain array methods:
['apple','pear','banana', 'peach'].map(function(fruit){
if (fruit === 'apple') {
return undefined;
}
return 'I love to eat ' + fruit;
}).filter(function (item) { return item; });
update
One of the tenants of functional programming like this is that you create simple building blocks that do not have side effects. What the OP is describing is essentially adding a side-effect to .map, and this type of behavior should be discouraged.
The answer above can be reduced even further.
This code snippet can actually be reduced even further. Always avoid pushing into array if you can imo.
var result = ['apple','pear','banana', 'peach'].reduce(function(prev, curr){
if (curr === 'apple') {
return prev;
}
return prev.concat(curr);
}, []);

Should I use jQuery.inArray()?

I'm doing very frequent searches in arrays of objects and have been using jQuery.inArray(). However, I'm having speed and memory issues and one of the most called methods according to my profiler is jQuery.inArray(). What's the word on the street about its performance? Should I switch to a simple for loop?
My specific function is:
function findPoint(point, list)
{
var l = list.map(function anonMapToId(p) { return p.id });
var found = jQuery.inArray(point.id, l);
return found;
}
Is perhaps list.map() is more to blame?
Well internally inArray makes a simple loop, I would recommend you to check if there is a native Array.prototype.indexOf implementation and use it instead of inArray if available:
function findPoint(point, list) {
var l = list.map(function anonMapToId(p) { return p.id });
var found = ('indexOf' in Array.prototype) ? l.indexOf(point.id)
: jQuery.inArray(point.id, l);
return found;
}
The Array.prototype.indexOf method has been introduced in browsers that implement JavaScript 1.6, and it will be part of the ECMAScript 5 standard.
Native implementations are way faster than non native ones.
What you really want is a Array.prototype.filter.
function findPoint(point, list)
{
return list.filter(function anonFilterToId(p) {
return p.id === point.id;
}).length > 0;
}
Even is the inArray function were slow, you're still creating a full new array for every search. I suppose it would be better to redesign this search, by e.g. creating the id-list before finding the points, and using that one to search into:
I'm doing a join of the array to turn it into a string and avoid the loop section like this :
var strList = ","+array.join(",")+",";
return strList.indexOf(","+search+",") !== -1 ? true : false;
if the array is huge, it can hurt, but for a small list it's much faster than the loop solution
PS I'm adding an ending coma to avoid look a like
I always use lastIndexOf when I want to know if there's a string in my array.
So, its something like this:
var str = 'a';
var arr = ['a','b','c'];
if( arr.lastIndexOf(str) > -1){
alert("String " + str + " was found in array set");
} else {
alert("String " + str + " was not found");
}
If you just want to find a string in array, I do believe this might be the best practice.

Categories

Resources