unexpected token break in ternary conditional - javascript

The function below is intended to return the values from a (potentially nested) object as an array - with the list parameter being any object. If I move my break statement to after the for loop, I don't get any errors, but of course then my function doesn't behave as needed. What's wrong with the way I'm using break?
function listToArray(list) {
var objectArray = [];
function objectPeeler() {
let peel = Object.getOwnPropertyNames(list);
for(var i = 0; i < peel.length; i++) {
list[peel[i]] && typeof list[peel[i]] != 'object' ?
objectArray.push(list[peel[i]]):
list[peel[i]] ?
(list = list[peel[i]], objectPeeler()) :
break;
}
return objectArray;
}
objectPeeler();
}

In case anyone else has this issue: ternary operators only work with value expressions, not statements (like break) and aren't meant to be used in these cases.
This works:
function listToArray(list) {
var objectArray = [];
function objectPeeler() {
let peel = Object.getOwnPropertyNames(list);
for(var i = 0; i < peel.length; i++) {
list[peel[i]] != null && typeof list[peel[i]] != 'object' ?
objectArray.push(list[peel[i]]):
list[peel[i]] ?
(list = list[peel[i]], objectPeeler()): null;
}
}
objectPeeler();
return objectArray;
}
But using the jquery .next method allows a better solution:
function listToArray(list) {
var array = [];
for (var obj = list; obj; obj = obj.next)
array.push(obj.value);
return array;
}

why not writing something like this :
var obj = { 0: "a", 1: "b", 2: "c"}; //test target
var objectArray = [];
var keyArray = Object.getOwnPropertyNames(obj);
for (var i = 0; i < keyArray.length; i++) objectArray.push(obj[keyArray[i]]);
console.log(objectArray); // test result

Related

Javascript: attach child several deep to object?

If I want to iterate through a list like this:
var inputArray = [
'CHILD0',
'PARENT0_CHILD1',
'PARENT1_PARENT2_CHILD2',
'PARENT1_PARENT3_CHILD3',
'PARENT1_PARENT3_CHILD4'
];
And have it return an object like so:
var resultObject = {
CHILD0: null,
PARENT0: {CHILD1: null},
PARENT1: {
PARENT2: {CHILD2: null},
PARENT3: {
CHILD3: null,
CHILD4: null
}
}
};
How could I iterate through the array to return the result?
I've got something like this:
function iterateArray (inputArray) {
var _RESULT = {};
for (var i = 0; i < inputArray.length; i += 1) {
var _inputName = inputArray[i];
var _inputNameArray = _input.split('_');
var _ref;
for (var n = 0; n < _inputNameArray.length; n += 1) {
//...?
}
_RESULT[_ref] = null;
}
return _RESULT;
}
var resultObject = iterateArray(inputArray);
Not sure what to do from this point. Think I might need a recursive function of sorts. Thoughts?
With minimal changes to your code:
function iterateArray (inputArray) {
var _RESULT = {};
for (var i = 0; i < inputArray.length; i += 1) {
var _inputName = inputArray[i];
var _inputNameArray = _inputName.split('_');
var _ref = _RESULT;
for (var n = 0; n < _inputNameArray.length - 1; n += 1) {
if (!_ref[_inputNameArray[n]]) _ref[_inputNameArray[n]] = {};
_ref = _ref[_inputNameArray[n]];
}
_ref[_inputNameArray[n]] = null;
}
return _RESULT;
}
You never need recursion, as it can always be unwrapped into iteration (and vice versa). Things are just sometimes much nicer one way or another.
EDIT: What's with all the underscores? :)
EDIT2: The key point to understanding this is reference sharing. For example:
For CHILD0, _ref = _RESULT means both of the variables are pointing at the same {}. When you do _ref['CHILD0'] = null, it is the same as doing _RESULT['CHILD0'] = null.
For PARENT0_CHILD1, first _ref = _RESULT as above, so _ref['PARENT0'] = {} is the same as _RESULT['PARENT0'] = {}. Then we switch the meaning of _ref to be the same thing as _RESULT['PARENT0']; when we assign _ref['CHILD1'] = null, it is the same as assigning _RESULT['PARENT0']['CHILD1'] = null.

In Javascript, is there an equivalent of a "find if", or a compact way of doing what I'm trying to do?

I have an ugly piece of Javascript code
for (var k = 0; k < ogmap.length; ++k)
{
if (ogmap[k]["orgname"] == curSelectedOrg)
{
ogmap[k]["catnames"].push(newCatName);
break;
}
}
Actually, I have a lot of pieces like that in my web app.
I'm wondering if there's a way to make it prettier and compacter. I know there are nice ways of doing this in other languages, like using find_if in C++ (http://www.cplusplus.com/reference/algorithm/find_if/) or FirstOrDefault in C# or fancy LINQ queries in C#.
At the very least, help me make that slightly more readable.
I'd say that you can just write yourself a utility function and then use it whenever necessary.
// finds the first object in the array that has the desired property
// with a value that matches the passed in val
// returns the index in the array of the match
// or returns -1 if no match found
function findPropMatch(array, propName, val) {
var item;
for (var i = 0; i < array.length; i++) {
item = array[i];
if (typeof item === "object" && item[propName] === val) {
return i;
}
}
return -1;
}
And, then you can use it like this:
var match = findPropMatch(ogmap, "orgname", curSelectedOrg);
if (match !== -1) {
ogmap[match]["catnames"].push(newCatName);
}
var find_if = function (arr, pred) {
var i = -1;
arr.some(function (item, ind) {
if (pred(item)) {
i = ind;
return true;
}
});
return i;
}
Call it like
var item_or_last = find_if(_.range(ogmap.length), function (item) {
return item["orgname"] == curSelectedOrg
});
Or without underscore.js
var range = function (a, b) {
var low = a < b ? a : b;
var high = a > b ? a : b;
var ret = [];
while (low < high) {
ret.push(low++);
}
return ret;
}
var item_or_last = find_if(range(0, ogmap.length), function (item) {
return item["orgname"] == curSelectedOrg
});
This lets you declare what you are looking for instead of looping over items and checking each one.

Finding an Object's value from an Array

Is there a simpler (or more efficient) way of achieving the following:
var _dataObjects = [{id:0, data:"data0", nextID:1},
{id:1, data:"data1", nextID:2},
{id:2, data:"data2", nextID:3} .. etc.];
generateNextPieceOfData();
function generateNextPieceOfData(){
var len = _dataObjects.length;
for ( var i = 0; i < len; i ++ ) {
var nextDataID = _dataObjects[i].nextID;
var nextData;
for ( var j = 0; j < len; j ++ ) {
if( _dataObjects[j].id == nextDataID ){
nextData = _dataObjects[j].data;
break;
}
}
}
}
The above example is abstracted from the problem I'm having and I realise the ID numbers are sequential in this instance but in the real problem nextID numbers do not run sequentially.
Thanks in advance.
Use the right data structure for your problem. Since you want to find an object by ID, create a hash map with the IDs as keys and objects as values:
var object_map = {};
for(var i = 0, l = _dataObjects.length; i < l; i++) {
objects[_dataObjects[i].id] = _dataObjects[i];
}
Then getting the next object is simply:
var next_object = object_map[someObject.nextID];
You still have iterate until some terminal condition is met though. For example:
function generatePath(id_a, id_b) {
var obj = object_map[id_a];
var path = [obj];
while (obj && obj.id !== id_b) {
obj = object_map[obj.nextID];
path.push(obj);
}
return path;
}
If your code works sequentially only, then you can sort the items by id or whatever and your code should work right? Try this:
_dataObjects = _dataObjects.sort(function(a, b) {
return a.id > b.id;
});

Javascript Recursion for creating a JSON object

needing some advice on how to do this properly recursively.
Basically what I'm doing, is entering in a bunch of text and it returns it as JSON.
For example:
The text:
q
b
name:rawr
Returns:
[
"q",
"b",
{
"name": "rawr"
}
]
And the following input:
q
b
name:rawr:awesome
Would return (output format is not important):
[
"q",
"b",
{
"name": {
"rawr": "awesome"
}
}
]
How can I modify the following code to allow a recursive way to have objects in objects.
var jsonify = function(input){
var listItems = input, myArray = [], end = [], i, item;
var items = listItems.split('\r\n');
// Loop through all the items
for(i = 0; i < items.length; i++){
item = items[i].split(':');
// If there is a value, then split it to create an object
if(item[1] !== undefined){
var obj = {};
obj[item[0]] = item[1];
end.push(obj);
}
else{
end.push(item[0]);
}
}
// return the results
return end;
};
I don't think recursion is the right approach here, a loop could do that as well:
var itemparts = items[i].split(':');
var value = itemparts.pop();
while (itemparts.length) {
var obj = {};
obj[itemparts.pop()] = value;
value = obj;
}
end.push(value);
Of course, as recursion and loops have equivalent might, you can do the same with a recursive function:
function recurse(parts) {
if (parts.length == 1)
return parts[0];
// else
var obj = {};
obj[parts.shift()] = recurse(parts);
return obj;
}
end.push(recurse(items[i].split(':')));
Here is a solution with recursion:
var data = [];
function createJSON(input) {
var rows = input.split("\n");
for(var i = 0; i < rows.length; i++) {
data.push(createObject(rows[i].split(":")));
}
}
function createObject(array) {
if(array.length === 1) {
return array[0];
} else {
var obj = {};
obj[array[0]] = createObject(array.splice(1));
return obj;
}
}
createJSON("p\nq\nname:rawr:awesome");
console.log(data);

Initializing a 'multidimensional' object in javascript

I'm having an issue with trying to populate a multidimensional object in javascript before all of the dimensions are defined.
For example this is what I want to do:
var multiVar = {};
var levelone = 'one';
var leveltwo = 'two';
multiVar[levelone][leveltwo]['levelthree'] = 'test'
It would be extremely cumbersome to have to create each dimension with a line like this:
var multiVar = {};
multiVar['levelone'] = {};
multiVar['levelone']['leveltwo'] = {};
multiVar['levelone']['leveltwo']['levelthree'] = 'test'
The reason why I need to do it without iterative priming is because I don't know how many dimensions there will be nor what the keys it will have. It needs to be dynamic.
Is there a way to do that in a dynamic way?
You could write a function which ensures the existence of the necessary "dimensions", but you won't be able to use dot or bracket notation to get this safety. Something like this:
function setPropertySafe(obj)
{
function isObject(o)
{
if (o === null) return false;
var type = typeof o;
return type === 'object' || type === 'function';
}
if (!isObject(obj)) return;
var prop;
for (var i=1; i < arguments.length-1; i++)
{
prop = arguments[i];
if (!isObject(obj[prop])) obj[prop] = {};
if (i < arguments.length-2) obj = obj[prop];
}
obj[prop] = arguments[i];
}
Example usage:
var multiVar = {};
setPropertySafe(multiVar, 'levelone', 'leveltwo', 'levelthree', 'test');
/*
multiVar = {
levelone: {
leveltwo: {
levelthree: "test"
}
}
}
*/

Categories

Resources