In the code below I can easily enter into a subarray within the array with current = current[0].
var root = [
[
'Value 1',
]
];
var current = root;
current = current[0];
current.push('Value 2');
document.write(JSON.stringify(root));
How can I do the reverse and go up a level? In this example, current would become:
[['Value 1', 'Value 2']]
The only way I can think of doing this would be looping, but duplicates would be very probably and problematic. All I've found online is looping, which won't work as a mention in the last sentence.
EDIT
I'm looping through a large string and converting it to a tree. Certain characters will require a indent in the tree or a separate branch, while others will require an outdent and return to the parent function. I've achieved the indents by having a current variable just enter a new subarray as suggested here. I just need a way to exit with a different character.
You can't.
Arrays have no concept of a "parent" or anything. They don't care where their references are being held. However, if you really really need to, you can implement the concept of a "parent" yourself using a simple recursive function setting properties of the arrays - see below:
var root = [
[
'Value 1',
]
];
function setParents(root) {
for(var i = 0; i < root.length; i++) {
if(Array.isArray(root[i])) {
root[i].parent = root;
setParents(root[i]);
}
}
}
setParents(root);
var current = root;
current = current[0];
current.push('Value 2');
document.write(JSON.stringify(root));
current = current.parent;
console.log(current);
This makes use of the fact that array properties don't show up when logged or serialized as JSON, only their elements. So they're kind of "hidden" in a sense. It's a bit hacky but could work for you.
However, I recommend you simply avoid overwriting current - there's not really a great need to use it like a cursor traversing some hierarchy structure.
Simply pushing BEFORE setting current variable will work.
var root = [
[
'Value 1',
]
];
var current = root;
root.push("AAA");
current = current[0];
current.push('Value 2');
document.write(JSON.stringify(root));
Related
I'm super newbie in coding and I need help to achieve this code.
I'm trying to get a random item (in pairs) from an array and then remove it from this array until user gets to the last item or 60 days have gone from using the service (cookie?)... I have build a script with the help of other questions here in stackoverflow and here is my results so far.
`<script>
var randomizer = document.getElementById("getImgBut");
var dog1 = '/app/wp-content/mediaApp/yo-creo-mi-realidad/01F.jpg';
var dog2 = '/app/wp-content/mediaApp/yo-creo-mi-realidad/01B.jpg';
var dogpics=[dog1,dog2];
var yourPics = [
dogpics,
[ '/app/wp-content/mediaApp/yo-creo-mi-realidad/02F.jpg', '/app/wp-content/mediaApp/yo-creo-mi-realidad/02B.jpg' ],
[ '/app/wp-content/mediaApp/yo-creo-mi-realidad/03F.jpg', '/app/wp-content/mediaApp/yo-creo-mi-realidad/03B.jpg' ],
[ '/app/wp-content/mediaApp/yo-creo-mi-realidad/04F.jpg', '/app/wp-content/mediaApp/yo-creo-mi-realidad/04B.jpg' ],
[ '/app/wp-content/mediaApp/yo-creo-mi-realidad/05F.jpg', '/app/wp-content/mediaApp/yo-creo-mi-realidad/05B.jpg' ],
[ '/app/wp-content/mediaApp/yo-creo-mi-realidad/06F.jpg', '/app/wp-content/mediaApp/yo-creo-mi-realidad/06B.jpg' ] //This array has 52 cards but I cutted it for example purposes
];
function get_random_number(array){
return Math.floor(Math.random() * array.length |0);
} // here is where I have tried to modify with other scripts like the one in this page https://stackoverflow.com/questions/38882487/select-random-item-from-array-remove-it-restart-once-array-is-empty with no success
randomizer.addEventListener("click", function() {
var rand_number = get_random_number(yourPics);
console.log(rand_number);
document.getElementById('img1').src = yourPics[rand_number][0];
document.getElementById('img2').src = yourPics[rand_number][1];
});
var card = document.querySelector('.card');
card.addEventListener( 'click', function() {
card.classList.toggle('is-flipped');
});
</script>`
Thank you for your help!
I don't fully understand what you mean by "remove in pairs", but I'll answer presuming you mean you wish to remove the image ending in 02F.jpg at the same time as removing the image ending in 02B.jpg, and then 03F.jpg at the same time as 03B.jpg.
The solution to this that I will propose is that we will structure your data a bit differently to begin with. That is, if those images, the "B image" and "F image" are linked, we could keep them in the same `javascript object. This would look like:
var yourPics = [
{
bImage: '/app/wp-content/mediaApp/yo-creo-mi-realidad/02F.jpg',
fImage: '/app/wp-content/mediaApp/yo-creo-mi-realidad/02B.jpg'
},
{
bImage: '/app/wp-content/mediaApp/yo-creo-mi-realidad/03F.jpg',
fImage: '/app/wp-content/mediaApp/yo-creo-mi-realidad/03B.jpg'
}...]
This would then be an array of objects, rather than strings. We can access the bImage property of an object with just
myObject = yourPics[0]
myObject.bImage
We could delete one of those objects those at random via splice.
myRandomlyRemovedObject = yourPics.splice(myIndexToDeleteFrom, 1) would remove 1 object from yourPics at position of myIndexToDeleteFrom, which you presumably would choose randomly. myRandomlyRemovedObject would be assigned to the one object we removed.
I think this object based approach is safer since you will know for a fact that you will removed both matching strings at the same time.
I'm working with a large dataset that needs to be efficient with its Mongo queries. The application uses the Ford-Fulkerson algorithm to calculate recommendations and runs in polynomial time, so efficiency is extremely important. The syntax is ES6, but everything is basically the same.
This is an approximation of the data I'm working with. An array of items and one item being matched up against the other items:
let items = ["pen", "marker", "crayon", "pencil"];
let match = "sharpie";
Eventually, we will iterate over match and increase the weight of the pairing by 1. So, after going through the function, my ideal data looks like this:
{
sharpie: {
pen: 1,
marker: 1,
crayon: 1,
pencil: 1
}
}
To further elaborate, the value next to each key is the weight of that relationship, which is to say, the number of times those items have been paired together. What I would like to have happen is something like this:
// For each in the items array, check to see if the pairing already
// exists. If it does, increment. If it does not, create it.
_.each(items, function(item, i) {
Database.upsert({ match: { $exist: true }}, { match: { $inc: { item: 1 } } });
})
The problem, of course, is that Mongo does not allow bracket notation, nor does it allow for variable names as keys (match). The other problem, as I've learned, is that Mongo also has problems with deeply nested $inc operators ('The dollar ($) prefixed field \'$inc\' in \'3LhmpJMe9Es6r5HLs.$inc\' is not valid for storage.' }).
Is there anything I can do to make this in as few queries as possible? I'm open to suggestions.
EDIT
I attempted to create objects to pass into the Mongo query:
_.each(items, function(item, i) {
let selector = {};
selector[match] = {};
selector[match][item] = {};
let modifier = {};
modifier[match] = {};
modifier[match]["$inc"] = {};
modifier[match]["$inc"][item] = 1
Database.upsert(selector, modifier);
Unfortunately, it still doesn't work. The $inc breaks the query and it won't let me go more than 1 level deep to change anything.
Solution
This is the function I ended up implementing. It works like a charm! Thanks Matt.
_.each(items, function(item, i) {
let incMod = {$inc:{}};
let matchMod = {$inc:{}};
matchMod.$inc[match] = 1;
incMod.$inc[item] = 1;
Database.upsert({node: item}, matchMod);
Database.upsert({node: match}, incMod);
});
I think the trouble comes from your ER model. a sharpie isn't a standalone entity, a sharpie is an item. The relationship between 1 item and other items is such that 1 item has many items (1:M recursive) and each item-pairing has a weight.
Fully normalized, you'd have an items table & a weights table. The items table would have the items. The weights table would have something like item1, item2, weight (in doing so, you can have asymmetrical weighting, e.g. sharpie:pencil = 1, pencil:sharpie = .5, which is useful when calculating pushback in the FFA, but I don't think that applies in your case.
Great, now let's mongotize it.
When we say 1 item has many items, that "many" is probably not going to exceed a few thousand (think 16MB document cap). That means it's actually 1-to-few, which means we can nest the data, either using subdocs or fields.
So, let's check out that schema!
doc =
{
_id: "sharpie",
crayon: 1,
pencil: 1
}
What do we see? sharpie isn't a key, it's a value. This makes everything easy. We leave the items as fields. The reason we don't use an array of objects is because this is faster & cleaner (no need to iterate over the array to find the matching _id).
var match = "sharpie";
var items = ["pen", "marker", "crayon", "pencil"];
var incMod = {$inc:{}};
var matchMod = {$inc:{}};
matchMod.$inc[match] = 1;
for (var i = 0; i < items.length; i++) {
Collection.upsert({_id: items[i]}, matchMod);
incMod.$inc[items[i]] = 1;
}
Collection.upsert({_id: match}, incMod);
That's the easy part. The hard part is figuring out why you want to use an FFA for a suggestion engine :-P.
I have a collection that has a 10 x 10 2-d array field. When I update an element in this array, the entire field is sent back to me as changed.
Is there a better way to do the update part?
I'm new to noSQL so maybe I just need to rethink my database setup. This would be a little depressing as I love the simplicity of being able to map javascript objects directly to fields in a single collection. I, however, am not willing to lose ~500 bytes of overhead every time I update this thing.
Is there a way to force Meteor to update the client with more fine-grained changes? Or is this a limitation of how Meteor Livequery works?
Thanks!
The problem is that DDP only supports changed messages at the top-level field granularity. With your current structure, any change to a sub-field of squares will result in the entire squares field being transmitted to the client.
One alternative is to store each element of the 2D array as a separate, top-level field. Below is a complete working example using a - character to separate the elements:
var pool2squares = function(pool) {
var squares = [];
_.each(pool, function(value, key) {
var parts = key.split('-');
if (parts[0] === 'squares') {
var i = Number(parts[1]);
var j = Number(parts[2]);
if (squares[i] == null)
squares[i] = [];
squares[i][j] = value;
}
});
return squares;
};
Pools = new Mongo.Collection('pools', {
transform: function(doc) {
return _.extend(doc, {squares: pool2squares(doc)});
}
});
Meteor.startup(function() {
Pools.insert({
'squares-0-0': 'a',
'squares-0-1': 'b',
'squares-1-0': 'c',
'squares-1-1': 'd'
});
console.log(Pools.findOne().squares);
});
Here we are using a collection transform to add a squares property to each Pool document whenever it's fetched. The above code will print:
[ [ 'a', 'b' ], [ 'c', 'd' ] ]
To update a Pool:
Pools.update(id, {$set: {'squares-3-4': 'hello'}});
I have an array that stores the values:
var array = [['favorite color'],['black','red']]
to get black I would:
document.write(array[0][1][0]);
then if i append to the array another question [['favorite thing']['box','ball']]
If I wanted ball I would:
document.write.array[1][1][1];
I am having trouble understanding arrays. I want an array with one question and multiple answers then I want to loop through them and display everything. I can do the loop but I am unsure how to find things in nested arrays once I create them.
Use a combination of objects (which work like dictionaries) and arrays. For example:
var array = [
{'question' : 'favorite color', 'choices' : ['black','red'] },
{'question' : 'favorite thing', 'choices' : ['box','ball'] }
]
for( var i = 0; i < array.length; i++ ) {
var question = array[i]['question'];
var choices = array[i]['choices'];
// here you can display / write out the questions and choices
}
Bearing in mind, creating a class and using a constructor or init methods would probably be better to encapsulate the idea of questions and answers. But the above is the basic idea.
var array = [['favorite color'],['black','red','blue']];
document.writeln(array[1][1]);
document.write(array[1][2]);
Would print red then blue see it working live : http://jsfiddle.net/HJ872/
How?
array[0] => gets an *array* = ['favorite color']
=> array[0][0] gets this first element `favorite color`
array[1] => also gets this array = ['black','red','blue']
=> and then [1][1] will get 'red', [1][2] will get `blue`
I'm building a web-app that needs to process nested geographical data to both display in a treeview, but also be searchable. The raw data looks something like this:
id:1, name:UK
id:2: name: South-East, parentId: 1
id:3: name: South-West, parentId:1
id:4: name: Berkshire, parentId: 2
id:5: name: Reading, parentId: 4
and I want it to look something like this:
id:1: name UK, children[
{id: 2, name: South-East, children:[
{id:4: name: Berkshire, children: [
{id:5: name: Reading}
]
},
{id:3: name: South-West}
]
so that each geographical location has a "children" array property, which contains all the sub-areas, each of which has another "children" array property, and so on. It would probably make sense to have a "parent" property as well, so I could navigate from any child item up to its parent.
I also need to be able to search the list - searching each branch of the tree may take some time, so perhaps I need to also keep the list in flat format.
I know how I could do this in JavaScript (possibly using jLinq for filtering, grouping and sorting), but I don't know how fast it would be. Has anyone already had a go at this in JavaScript or know of any general algorithms/patterns that solve this?
It's actually not that difficult to make the flat array into a tree and do it pretty quickly, I think the slowest bit will be getting the definition of the data structure onto the page (hence why you're lazy loading was successful!). This can be helped though by making the data structure definition smaller.
In Javascript I did it like this:
//Make the data definition as small as possible..
//each entry is [ name, parent_pos_in_array]..
//note: requires that a parent node appears before a child node..
var data = [
["UK", -1], //root..
["South-East", 0],
["South-West", 0],
["Berkshire", 1],
["Reading", 3]
//...etc...
];
//Turns given flat arr into a tree and returns root..
//(Assumes that no child is declared before parent)
function makeTree(arr){
//Array with all the children elements set correctly..
var treeArr = new Array(arr.length);
for(var i = 0, len = arr.length; i < len; i++){
var arrI = arr[i];
var newNode = treeArr[i] = {
name: arrI[0],
children: []
};
var parentI = arrI[1];
if(parentI > -1){ //i.e. not the root..
treeArr[parentI].children.push(newNode);
}
}
return treeArr[0]; //return the root..
}
var root = makeTree(data);
To test the speed on a larger list you can run:
var data = [['root', -1]];
for(var i = 1; i < 100000; i++){
var parentI = Math.floor(Math.random()*(i-1));
data.push(['a_name', parentI]);
}
var start = new Date().getTime();
var tree = makeTree(data);
var end = new Date().getTime();
console.log('Took: ' + (end-start) + 'ms.');
With 100000 elements in the array it takes < 200ms on my old desktop. Not sure what kind of performance is acceptable though!
If you have a simple id & parent-id objects array with no other clue on the level, it's a tough task to generate the nested form. I would assume recursive approaches won't be practical in long lists. The best method that i could come up with so far is sorting that array in such a way that all children come after their parents. Parents and children and even the root objects can be mixed but a child must come after it's parent. Assuming that the object structure is like var data = [{id: KL442, pid: HN296}, {id: ST113, pid: HN296}, {id: HN296, pid: "root"},...] Yet sorting is the first phase of the job. While sorting we can generate a LUT (look up table) to access the parents almost at no cost. At the exit of the outer loop just one single instruction lut[a[i].id]=i; is sufficient for this. This makes the job enormously fast at the nesting stage. This is the sorting and LUT preparation phase.
function sort(a){
var len = a.length,
fix = -1;
for (var i = 0; i < len; i++ ){
while(!!~(fix = a.findIndex(e => a[i].pid == e.id)) && fix > i) [a[i],a[fix]] = [a[fix],a[i]];
lut[a[i].id]=i;
}
return a;
}
Once you have it sorted than a reverse iteration is the only thing you have to do to get your nested structure. So that you now have your data array sorted and LUT prepared, then this is the code for nesting.
for (var i = sorted.length-1; i>=0; i--)
sorted[i].pid != "root" && (!! sorted[lut[sorted[i].pid]].children
&& sorted[lut[sorted[i].pid]].children.push(sorted.splice(i,1)[0])
|| (sorted[lut[sorted[i].pid]].children = [sorted.splice(i,1)[0]]));
For a working sample you can check a previous answer of mine.
With Lodash:
var index = _.mapKeys(data,'id');
var obj = {};
_.each(index,function(v){
if(!v.parentId){
obj[v.id]=v;
}else{
if(!index[v.parentId].children){
index[v.parentId].children=[];
}
index[v.parentId].children.push(v);
}
});
Demo is here