In JavaScript, how would I create a two-dimensional object from a string of values, in which the first value would be the name, the last is the content, and all other values in between are properties?
For example, I have a string "capitals,Asia,China,Beijing" and I want the code to split this string into four values and create an object capitals["Asia","China"] = "Beijing";.
How could I do that?
In a complete code piece that would look like this:
<script>
Values = "capitals,Asia,China,Beijing";
Values = Values.split(",");
alert(capitals["Asia","China"]);
</script>
I want the alert box to show me the word Beijing.
How could I do that?
JavaScript does not have two-dimensional arrays or objects that you can access using array[index1, index2] as in some other languages. To do this, you have to use nested objects/arrays, such as
capitals["Asian"]["China"]
To create these, you can do something like:
function makeEntry(obj, str) {
const parts = str.split(','); // array of comma-delimited values
const value = parts.pop(); // final value ("Beijing")
const final = parts.pop(); // final property ("China")
// Find nested property, creating empty object if not there.
for (let i = 0; i < parts.length; i++) {
const part = parts[i];
if (!(parts in obj)) obj[part] = {};
obj = obj[part];
}
// Set final value.
obj[final] = value;
}
const data = {};
makeEntry(data, "capitals,Asian,China,Beijing");
console.log(data);
console.log(data.capitals["Asian"]["China"]);
This code will work even if there are more levels, such as "capitals,Asia,East Asia,China,Beijing".
Note that there is no way to create a variable in JS given a name. Therefore, we provide an initial object, and build the nest structure within it.
Another approach
Another approach is to create a single-level object with keys such as "capitals,Asian,China". That's easier to create, but might be more inconvenient to access. For example, there would be no easy way to find all the Asian capitals. Below, I'm using regexp to pick apart the input into the first part and the final value.
function makeEntry(obj, str) {
const [, key, value] = str.match(/(.*),([^,]+)$/);
obj[key] = value;
}
const data = {};
makeEntry(data, "capitals,Asian,China,Beijing");
console.log(data);
console.log(data["capitals,Asian,China"]);
You can use WeakMap to set the key of the WeakMap object to an object; Array.prototype.shift(), Array.prototype.splice(), Array.prototype.pop() to set the value of the WeakMap object instance.
let Values = "capitals,Asian,China,Beijing";
Values = Values.split(",");
const capitals = {[Values.shift()]:Values.splice(0, 2)};
const wm = new WeakMap;
wm.set(capitals, Values.pop());
console.log(wm.get(capitals));
You can alternatively set the property of an object to the result of JSON.stringify() called on Values.splice(1, 2)
let Values = "capitals,Asian,China,Beijing";
Values = Values.split(",");
const key = JSON.stringify(Values.splice(1, 2));
console.log(key);
const map = {[Values.shift()]:{[key]:Values.pop()}};
console.log(map.capitals[key]);
Related
I have a string as "a.b.c.d:50" so i want to form an array with the above string as t[a][b][c][d]=50. so i have tried to split the code and form but this length of n values will generate dynamically. please let me know how we can achieve this.for fixed arrays i tried as below but not able to make this as for n number of arrays.
var str1="a.b.c.d:50";
var str=str1.split(":");
var dump=str[0].split(".");
t[dump[0]][dump[1]][dump[2]][dump[3]]=dump[4]
then result will be t[a][b][c][d]=50
You could take the JSON string, parse it and iterate all key/value pairs for a nested structure by saving the last key and crate new objects if not exist and assign the vlaue with the last property.
function setValue(object, path, value) {
var last = path.pop();
path.reduce((o, k) => o[k] = o[k] || {}, object)[last] = value;
}
var json = '{"subscriber.userTier.segment": "Red"}',
object = {};
Object
.entries(JSON.parse(json))
.forEach(([keys, value]) => setValue(object, keys.split('.'), value));
console.log(object);
Are you able to use ES6? This is something I just wrote quickly
var t = {a:{b:{c:{d:0}}}};
var str = "a.b.c.d:50"
var [chain, value] = str.split(':')
var parts = chain.split('.');
parts.slice(0, -1).reduce((c, v) => c[v], t)[parts[parts.length - 1]] = value;
console.log(t.a.b.c.d); // logs "50"
It works, however there is no error handling. If t['a']['b'] is undefined for example then you will get an uncaught TypeError, also if the string is in the incorrect format etc, it won't work.
At it's heart it uses reduce on the array ['a', 'b', 'c']. We pass t as the initial value for the reducer and then for each item in the array it does currentValue = currentValue[nextPart]. This will get you the object c, we then look at the last value in the parts array and set that property currentValue[lastPart] = value
That's a brief overview, hopefully you understand the rest of what's going on. If not feel free to ask :)
Quick and Dirty way of converting a string to a JSON object, if the string is constructed as a valid object.
var str = "a.b.c.d:50";
str = str.replace(/([a-z]){1}/gi, "\"$1\"");
str.split(".").forEach(function (value) {
str = str.replace(/\.(.*?)$/, ":{$1}");
});
var ar = JSON.parse("{"+str+"}");
console.log(ar);
I have a text file in which I have data on every line. It looks like this:
number0;text0
number1;text1
number2;text2
..and so on
So I loaded that text file into a variable via xmlhttprequest and then I converted it into an array using split by "\n" so now the result of lineArray[0] is number0;text0.. And now what I need is to split that array again so I could use number0 and text0 separately.
My idea being that I want to get the text0 by searching number0 for example lineArray[i][1] gives me texti..
Any ideas how to proceed now?
Thanks
You need to do an additional split on ; as split(';') so that lineArray[0][1], lineArray[1][1] and so on gives you text0, text1 and so on.
var str = `number0;text0
number1;text1
number2;text2`;
var lineArray = str.split('\n').map(function(item){
return item.split(';');
});
console.log(lineArray);
console.log(lineArray[0][1]);
console.log(lineArray[1][1]);
Knowing I'm late, still making a contribution.
As everyone else said, split it again.
let text = "number0;text0\nnumber1;text1\nnumber2;text2"
let data = text.split('\n');
var objects = {};
for (var i = 0; i < data.length; i++) {
let key = data[i].split(';')[0]; // Left hand value [Key]
let value = data[i].split(';')[1]; // Right hand value [Value]
// Add key and value to object
objects[key] = value;
}
// Access by property
console.log(objects);
Using forEach
let text = "number0;text0\nnumber1;text1\nnumber2;text2"
let data = text.split('\n');
var objects = {};
data.forEach((elem) => {
let key = elem.split(';')[0]; // Left hand value [Key]
let value = elem.split(';')[1]; // Right hand value [Value]
objects[key] = value;
});
// Access by property
console.log(objects);
Just use split again with ";", like that:
myVar = text.split(';');
like #Teemu, #Weedoze and #Alex said
Convert the array into an object
Make an object out of it with another String split. To do so you can use the .reduce method to convert the array of strings into an object.
const strings = ['number0;text0', 'number1;text1', 'number3;text3', 'number4;text4'] ;
const obj = strings.reduce((acc,curr) => {
const [key, value] = curr.split(';');
acc[key] = value;
return acc;
}, {});
console.log(obj)
This way you can access text4 buy calling obj['number4'].
More about .reduce
The reduce method works by looping through strings
on each step acc is the accumulator: it contains the object that is getting filled with key/value pairs.
cur is the current item in the step
const [key, value] = curr.split(';') will to split the string into two strings and assign each to a seperate variable: key and value. It's called destructuring assignment
then I assign the key/value pair to the accumulator
the .reducemethod will return the accumulator on his state on the last step of the loop
Something like this could do the trick:
let a = "number0;text0\nnumber1;text1\nnumber2;text2";
let lines = a.split('\n');
let vals = [];
for(let line of lines) {
vals.push(line.split(';'))
}
console.log(vals); // Output
The last four lines create an empty array and split on the ';' and append that value to the vals array. I assume you already have the something like the first 2 lines
I have the following code that calculates the highest value in my set of values:
var collection = [];
$histogram.find('li').each(function() {
collection.push($(this).data());
});
component.props.collection = collection;
// Find Histogram max value
collection.hasMax = function(value) {
return this.reduce(function(prev, curr) {
return prev[value] > curr[value] ? prev : curr;
});
};
// Assign Max Value
component.props.maxRange = collection.hasMax('value').value;
I need to create a second function that does the same, but for the lowest values, e.g. the function called hasMin. I thought it would be enough to just change the comparision here:
return prev[value] < curr[value] ? prev : curr;
but I tested it and it didn't work, can you help me with that?
JavaScript's built-in Math object has a static Math.min() method, which seems to solve your problem without the need for all that code you are using.
You can get the lowest value of an array by using JavaScript's destructuring assignment (to turn the array into a comma separated list of values) and pass that list to the method.
There's also Math.max().
let myData = [1,2,3,4,5,6,7,8,9,10];
console.log(Math.min(...myData));
console.log(Math.max(...myData));
You've indicated that collection is an array of objects and each object has a value property and you need to get the lowest and highest values in that object array so this will do it:
// This is just set up to emulate your data structure. Don't add this:
var sth = "test", sth2 = "test", sth3 = "test";
let component = { props: {} };
let collection = [{value:0, label: sth},{value:1, label: sth2},{value:3, label:sth3}];
// Assuming your data structure is set up, the following will get you there:
// Loop over the array of objects, extracting the value property of each object into a new array
let vals = collection.map(function(obj){
return obj.value; // Place the value of each object into an array
});
// Just set your object's properties to the min and max of the destructured array
component.props.minRange = Math.min(...vals);
component.props.maxRange = Math.max(...vals);
console.log(component.props.minRange, component.props.maxRange);
with ES5:
let sth = "test", sth2 = "test", sth3 = "test";
let component = { props: {} };
let collection = [{value:0, label: sth},{value:1, label: sth2},{value:3,
label:sth3}];
// Assuming your data structure is set up, the following will get you there:
// Loop over the array of objects, extracting the value property of each
object into a new array
let vals = collection.map(function(obj){
return obj.value; // Place the value of each object into an array
});
// Just set your object's properties to the min and max of the destructured array
component.props.minRange = Math.min.apply(Math,vals);
component.props.maxRange = Math.max.apply(Math,vals);
console.log(component.props.minRange, component.props.maxRange);
I am trying to parse a string in JS with a series of vars inline. The goal is to turn those vars into an object with name value pairs.
Example:
var hwStr = "color=blue+coreCnt=4+shell=aluminum+wireless=false";
I know I can parse the original string to get an array of name value pairs like this:
varArr = hwStr.split("+");
When I print that array I would get:
>color=blue,
>coreCnt=4,
>shell=aluminum,
>wireless=false
In order to create this object manually it would look like:
var hwSpec = {color: 'blue', coreCnt: 4, shell: 'aluminum', wireless: false};
My question is, how can I use a foreach statement to create an object that would have these as name value pairs.
To be fair JS is not my language, but I know that I SHOULD know this... This is probably a noob Question, any help would be great.
Gary C aka the UnKulMunki
After splitting on the plus signs, you can .reduce() the resulting array to process each key=value pair and add to an object:
var hwStr = "color=blue+coreCnt=4+shell=aluminum+wireless=false";
var obj = hwStr.split("+").reduce(function(o, item) {
item = item.split("=");
o[item[0]] = item[1];
return o;
}, {});
console.log(obj);
This is similar to using .forEach(), except instead of creating an empty object in a variable before calling .forEach() the empty object is passed as an argument to .reduce(). For this particular problem it doesn't make much difference, but in some cases .reduce() saves you having to create a temporary working variable.
EDIT: Note that my code creates all property values as strings - I don't think there's any way to know whether false should be treated as the boolean false or the string "false", unless you want to assume that all values that can be parsed as boolean or number should be treated as boolean or number.
First, you split the string at the + so you get an array of key/value pairs.
Then, you loop through those pairs and split each pair at the = to separate the key from the value. Then you assign the key as a property name and the value as the property value.
var hwStr = "color=blue+coreCnt=4+shell=aluminum+wireless=false";
// Split the string into an array of key/value pairs
var pairs = hwStr.split("+");
// Set up a new, empty object
var newObj = {};
// Loop through the key/value pairs array. The .forEach method takes
// a function as an argument that, itself, receives a value representing
// the current array item being iterated (a single key/value pair from
// the array in this case).
pairs.forEach(function(pair){
// Create a new property on the object with the key of the current pair
// and a value of the value of the current pair.
newObj[pair.split("=")[0]] = pair.split("=")[1];
});
console.log(newObj);
To do this, you have to use JSON's parse method to turn the string to javaScript object literal, this is how to do it:
var arr = hwStr.split("+");
var temp_arr = null;
var hwSpec = null;
var stringToConv = '{'; //string to convert to object literal
//iterate through the array
for (var i = 0; i < arr.length; i++){
temp_arr = arr[i].split("=");
stringToConv += '"' + temp_arr[0] + '":"' + temp_arr[1] + '"';
//check if is the last string in the arr
if (i === arr.length - 1){
stringToConv += '}'
}
else { //add comma
stringToConv += ",";
}
}
//convert to object using JSON
hwSpec = JSON.parse(stringToConv);
//your code here
not sure how to ask tbh :)
I'm used of PHP's associative arrays so much that I struggle to understand how to create an "named array" of objects.
Example:
I have two arrays, two ints and one boolean. This represents one of my entities. I have multiple entities on which I'm doing some work.
In PHP I would write:
$entitites[$entitity_id]['items'][] = $item;
$entitites[$entitity_id]['items_status'][] = $item_status;
$entitites[$entitity_id]['items_count']++;
and so on..
How do I do this with objects in JS?
var entities = {items:[], items_status: [], items_count: 0};
entities[entity_id].items.push(item)
How does one name his object for later access (via name or in my case, entity_id?)
This code doesnt work for me to this extend that my webpage goes blank without any errors produced :S
I also tried this:
var entities = {};
var entity = {items:[], items_status: [], items_count: 0};
but then I dont know how to always add values to already existing object in entities object and how to call that exact object via name eg. entity_id.
Halp :(
Keep entities as an object. Then you can just go ahead and add each entity_id as a key and an object which has all the details of that entity as the value.
var entities = {};
entities["1234"] = {
"items" : [],
"items_status" : [],
"items_count" : 0
};
There are 2 types involved here: Objects & Arrays.
Arrays are simple and you're probably familiar with them from any other language:
var myArray = []; // this is an empty array
myArray[0] = 1;
myArray[1] = 2;
myArray[2] = 3;
// you could also use "var myArray = [1, 2, 3];" instead
alert(myArray[1]); // alerts the value 2
Note: arrays are actually objects, and can have non-index properties as well
You can also use various array functions such as .push(), .pop(), .shift() and so on to mutate the array instead.
Objects share the square brackets notation, but the purpose is different:
var myObject = {}; // this is an empty object
myObject[0] = 1;
myObject[1] = 2;
myObject[2] = 3;
alert(myObject[1]); // alerts the value 2
// but also...
myObject['prop'] = 4;
alert(myObject['prop']); // alerts the value 4
// and
myObject.prop2 = 5;
alert(myObject.prop2); // alerts the value 5
// and lastly
alert(myObject.prop); // alerts the value 4
So while arrays are accessed by index, objects are accessed by property names.
As for your entities, it looks like an array of objects. Lets see how we can do that:
function Entity() {
this.items = [];
this.items_status = [];
this.items_count = 0;
}
var entitites = [];
entities.push(new Entity());
entities[0].items = [1, 2, 3];
entities[0].items_status = ['good', 'good', 'poor'];
entities[0].items_count = 3;
Or you can wrap insertion in a more elegant function:
Entity.prototype.insert(item, status) {
this.items.push(item);
this.items_status.push(status);
this.items_count++;
}
entities[0].insert(4, 'excellent!');
If you want to keep control of the indexes in your JS array you can do so by not using .push() :
var entities = [];
entities[5] = {items:[], items_status:[], items_count:0};
Just replace 5 by your integer entity_id variable, and there you go.
You can use a regular javascript object to create the associative array you're looking for.
Actually it's PHP's implementation that's abit off but all they do is call it different (associative array) to most other language that simply refer to it as an object or hash.
You can use numeric keys in JS and still access them with the [] square brackets.
It works like this:
var my_obj = {};
my_obj[5] = 'any value';
console.log(my_obj); // {5: 'any value'}
JS will not add any redundant undefined to missing indexes either so when looping over the collection you won't loop over undefined.
Also, I can access the object by using the key as a string or as number so you won't have to check if the key is the right type. Taken from the above example:
console.log(my_obj['5']); // 'any value'
console.log(my_obj[5]); // 'any value'
JS Objects are the equivelant of PHP assoc arrays except JS objects are much more flexible than PHP's associative arrays.
The only downside to this is that you can't have duplicate keys.
No two keys may exist that share the same name, in an array if you .push(an_item) it will create a new index making even a duplicate data entry unique but when overwriting a key with a new value only the last value will persist, mind that :)