Couchdb searching via multiple queries - javascript

I have the following map function to index each specific alphanumeric word inside my document so I can search for it.
Array.prototype.map = function(func) {
var i, r = [];
for(i = 0; i < this.length; i += 1) {
r[i] = func(this[i]);
}
return r;
};
Array.prototype.reduce = function(val, func) {
var i;
for (i = 0; i < this.length; i += 1) {
val = func(val, this[i]);
}
return val;
}
Array.prototype.uniq = function() {
return this.reduce([], function(list, e) {
if (list.indexOf(e) < 0) {
return list.concat([e]);
} else {
return list;
}
});
}
function(doc) {
var tokens;
if (doc.name) {
tokens = doc.name.toLowerCase().split(/[^A-Z0-9\-_]+/i).uniq();
tokens.map(function(token) {
emit(token, doc);
});
}
}
So if I do something like:
db.view('documents/keywords', { key: "hello" });
It will list every document with the word hello in it.
My question is, if I want to find something that has both the word hello and the word world, is there a more efficient way of doing this then doing two queries to my view, and then client side figure out which id's pop up in both queries?
My worry is it will start being troublesome at scale when I have 1,000 hellos and completely different amount of worlds

Related

Generate random tree using JavaScript

I am working on a project to generate random data structures for testing solutions for DSA problems. I am trying to form an algorithm that generates a random tree data structure that takes in the input of number of test cases and number of nodes. Since I cannot use pointers and references, I'm having trouble figuring out how to do this in javaScript.
So far I managed to get the basics down, however, I'm getting errors in my code
CODE:
const randnumgen = (min, max) => {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
};
function randtreegen(nodes) {
var string = "";
class Tree {
constructor(nodes) {
this.nodes = nodes;
this.adj = [];
}
addEdge(n, w) {
this.adj[n].push(w);
}
removeEdge(n, w) {
this.adj[n].forEach((elem) => {
if (elem === w) {
var index = this.adj[n].indexOf(elem);
if (index !== -1) this.adj[n].splice(index, 1);
}
});
}
isCyclicUtil(nodes, visited, recStack) {
if (visited[nodes] === false) {
visited[nodes] = true;
recStack[nodes] = true;
this.adj[n].forEach((elem) => {
if (!visited[elem] && this.isCyclicUtil(elem, visited, recStack))
return true;
else if (recStack[elem])
return true;
});
}
recStack[nodes] = false;
return false;
}
isCyclic() {
visited = new Array();
recStack = new Array();
for (var i = 0; i < this.nodes; i++) {
visited[i] = false;
recStack[i] = false;
}
for (var j = 0; j < this.nodes; i++) {
if (this.isCyclicUtil(j, visited, recStack))
return true;
}
return false;
}
}
container = new Set();
let t = new Tree(nodes);
for (var i = 1; i < nodes - 1; i++) {
var a = randnumgen(1, nodes);
var b = randnumgen(1, nodes);
var p = [a, b];
t.addEdge(p[0], p[1]);
while (container.has(`${p[0]},${p[1]}`) || t.isCyclic() === true) {
t.removeEdge(p[0], p[1]);
var a = randnumgen(1, nodes);
var b = randnumgen(1, nodes);
var p = [a, b];
t.addEdge(p[0], p[1]);
}
container.add(`${p[0]},${p[1]}`);
}
container.forEach((elem) => {
string += elem + '\n'
});
return string;
}
function treeGen(test_case, tree_nodes) {
var result = "";
while (test_case-- > 0) {
result += randtreegen(tree_nodes) + '\n';
}
return result;
}
const ans = treeGen(1, 5);
document.write(ans);
ERROR
TypeError: Cannot read property 'push' of undefined at /home/cg/root/7217808/main.js:18
this.adj[n].push(w);
My question is:
Is the Logic correct?
How to resolve the error to make it work?
P.S: I referred to this article on GeeksforGeeks.
The main issue is that you have not created the adj entries as empty arrays. So change:
this.adj = [];
To:
this.adj = Array.from({length: nodes}, () => []); // create that many empty arrays
But there are other issues as well:
Some pieces of code expect that nodes are numbered from 1, while other pieces of code expect a numbering starting at 0. As array indexes start from 0, it is more natural to also number your nodes starting from 0.
There are references to an unknown variable n, which should be nodes. NB: It is strange that you choose a plural name for this variable.
When you return true inside a forEach callback, you don't return from the outer function, but only from the forEach callback. This is not what you intended. Solve this by using a for...of loop.
In isCyclic you have a loop on j, but you increment with i++, so this loop will never end. Make it j++
The cycle test is not enough to ensure that your graph is a tree, because in a directed graph you can still have multiple paths between a node A and a node B, without cycles.
The loop in which edges are created needs one more iteration, so let it start from 0.
I would however suggest a slightly different approach for generating a random tree: shuffle all nodes randomly, and let the first node in that shuffled array be the root of the tree. Iterate all the other nodes, and let them be the destinations of new edges. Note that in a tree there is no node in which two edges arrive.
Then you can do a cycle test. I would however do this different too: perform a test before adding the edge. You can get all descendent nodes of the selected b node, and if a is in that set, then you should not create edge a,b.
Here is your adapted code. I removed the parts that are no longer used:
function randnumgen (min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
class Tree {
constructor(nodes) {
this.nodes = nodes;
this.adj = Array.from({length: nodes}, () => []);
}
addEdge(n, w) {
this.adj[n].push(w);
}
descendants(node) {
let visited = new Set([node]);
for (let node of visited) {
for (let elem of this.adj[node]) {
if (!visited.has(elem)) visited.add(elem);
}
}
return visited;
}
}
function shuffle(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
function randtreegen(nodes) {
let t = new Tree(nodes);
let [root, ...children] = shuffle([...Array(nodes).keys()]);
let edges = [];
let a;
for (let b of children) {
do {
a = randnumgen(0, nodes-1); // make zero based
} while (t.descendants(b).has(a));
t.addEdge(a, b);
edges.push([a, b]);
}
return edges.join("\n");
}
function treeGen(test_case, tree_nodes) {
var result = "";
while (test_case-- > 0) {
result += randtreegen(tree_nodes) + '\n';
}
return result;
}
const ans = treeGen(1, 5);
console.log(ans);

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.

Javascript: Improve four nested loops?

I have a complex array of objects with nested arrays. The following works to extract certain objects, but it's one of the ugliest things I've written.
Is there some javascript dark magic to do this elegantly?
function getEighthInsertionBlocks() {
var struct = Lifestyle.Pagination.structure;
var blocks = [];
for (var i = 0; i<struct.length; i++) {
var page = struct[i];
var layers = page.children;
for (var j=0; j<layers.length; j++) {
var layer = layers[j];
if (layer.className === 'EighthPageLayer' ) {
var rows = layer.children;
for (var k=0; k<rows.length; k++) {
var row = rows[k];
eBlocks = row.children;
for (var l=0; l<eBlocks.length; l++) {
blocks.push(eBlocks[l]);
}
}
}
}
}
return blocks;
}
Not that I'm a big fan of code golf, but ... this is horrible.
You could write a generic iterator, which would reduce the code into sequential blocks:
var iterator = function(collection, callback){
var length = collection.length;
var results = [];
var result;
for (var i = 0; i < collection.length; i++){
result = callback(colleciton[i], i);
if (result){
results = results.concat(result);
}
}
return results;
};
function getEighthInsertionBlocks() {
var struct = Lifestyle.Pagination.structure;
var layers = iterator(struct, function(page){ return page.children; });
var rows = iterator(layers, function(layer){
return layer.className === 'EighthPageLayer' ? layer.children : null;
});
return iterator(rows, function(eBlocks, index){ return eblocks[index]; });
}
I usually tend to like using forEach for the readability but this is subjective.
function isEighthPageLayer(layer){
return layer.className === "EighthPageLayer"
}
function getEighthInsertionBlocks(struct) {
var blocks = [];
struct.forEach(function(page){
page.layers
.filter(isEighthPageLayer)
.forEach( function(layer) {
layer.children.forEach(function(row){
row.children.forEach(function(eBlocks){
blocks.push(eBlocks);
});
});
});
});
});
return blocks;
}
This is an interesting challenge. To avoid deep nesting, you need a generic iterator that you can use recursively, yet there are a few special cases in your iteration. So, I tried to create a generic iterator that you can pass an options object to in order to specify the special conditions. Here's what I came up with. Since I don't have a sample data set, this is untested, but hopefully you see the idea:
function iterateLevel(data, options, level, output) {
console.log("level:" + level);
console.log(data);
var fn = options[level] && options[level].fn;
for (var i = 0; i < data.length; i++) {
if (!fn || (fn(data[i]) === true)) {
if (level === options.endLevel) {
output.push(data[i]);
} else {
iterateLevel(data[i].children, options, level + 1, output);
}
}
}
}
var iterateOptions = {
"1": {
fn: function(arg) {return arg.className === 'EighthPageLayer'}
},
"endLevel": 3
}
var blocks = [];
iterateLevel(Lifestyle.Pagination.structure, iterateOptions, 0, blocks);
The idea is that the options object can have an optional filter function for each level and it tells you how many levels to go down.
Working demo: http://jsfiddle.net/jfriend00/aQs6h/

Autocomplete using a trie

I am working on an autocompletion script and was thinking about using a trie. My problem is I want everything that matches to be returned. So for example I type in the letter r I want all entries starting with r to be returned. Then all entries starting with re etc. Is this feasible with a trie and how would it work. Also, if there is a better way I am open to suggestions. The reason I ask is it seems like it would be complicated and a whole lot of processing to return all of the nodes off of say the r branch.
And yes I may be reinventing the wheel, but I would like to learn how it works.
You can absolutely do it using a trie. Here is some code I threw together that can point you in the right direction:
var tokenTree = function (tokenArray) {
var createLetterObject = function (l) {
var pChildren = [];
var getMatchingWords = function (characterArr, availableWords, children) {
if (characterArr.length === 0) {
for (var child in children) {
if ({}.hasOwnProperty.call(children, child)) {
var currentChild = children[child];
var words = currentChild.getWords(characterArr);
for (var pos in words) {
if ({}.hasOwnProperty.call(words, pos)) {
availableWords.push(words[pos]);
}
}
if (currentChild.word) {
availableWords.push(currentChild.word);
}
}
}
} else {
var currentCharacter = characterArr.pop();
getMatchingWords(characterArr, availableWords, children[currentCharacter].children);
}
};
function doGetWords(wordPart) {
var len = wordPart.length;
var ar = [];
var wordList = [];
for (var ii = len - 1; ii >= 0; ii --) {
ar.push(wordPart[ii].toUpperCase());
}
getMatchingWords(ar, wordList, pChildren);
return wordList;
}
return {
letter: l,
children: pChildren,
parent: null,
word: null,
getWords: doGetWords
};
};
var startingPoint = createLetterObject();
function parseWord(wordCharacterArray, parent, fullWord) {
if (wordCharacterArray.length === 0) {
parent.word = fullWord;
return;
}
var currentCharacter = wordCharacterArray.pop().toUpperCase();
if (!parent.children[currentCharacter]) {
parent.children[currentCharacter] = createLetterObject(currentCharacter);
}
parseWord(wordCharacterArray, parent.children[currentCharacter], fullWord);
}
for (var counter in tokenArray) {
if ({}.hasOwnProperty.call(tokenArray, counter)) {
var word = tokenArray[counter];
if (!word) {
continue;
}
var ar = [];
var wordLength = word.length;
for (var ii = wordLength - 1; ii >= 0; ii--) {
ar.push(word[ii]);
}
parseWord(ar, startingPoint, word);
}
}
return startingPoint;
};
Usage
var tokens = ["Token", "words", "whohaa", "mommy", "test", "wicked"];
var tree = tokenTree(tokens);
var currentTokenSet = 'w';
var list = tree.getWords(currentTokenSet);
// it will return words,whohaa,wicked.
console.log(list)
I'm not saying this is anywhere near the best or most efficient way, but it should at least get you pointed in the right direction.
Here is a jsfiddle showing it working: https://jsfiddle.net/es6xp8h9/
Regarding the time to discover items at a root note, if you're doing this for an autocomplete, it's likely you won't be returning too many results per 'match'. If you wanted to trade off space for speed, you could store references to the 'top n' items at each of the nodes. This, of course, would require more time on update

fastest way to detect if duplicate entry exists in javascript array?

var arr = ['test0','test2','test0'];
Like the above,there are two identical entries with value "test0",how to check it most efficiently?
If you sort the array, the duplicates are next to each other so that they are easy to find:
arr.sort();
var last = arr[0];
for (var i=1; i<arr.length; i++) {
if (arr[i] == last) alert('Duplicate : '+last);
last = arr[i];
}
This will do the job on any array and is probably about as optimized as possible for handling the general case (finding a duplicate in any possible array). For more specific cases (e.g. arrays containing only strings) you could do better than this.
function hasDuplicate(arr) {
var i = arr.length, j, val;
while (i--) {
val = arr[i];
j = i;
while (j--) {
if (arr[j] === val) {
return true;
}
}
}
return false;
}
There are lots of answers here but not all of them "feel" nice... So I'll throw my hat in.
If you are using lodash:
function containsDuplicates(array) {
return _.uniq(array).length !== array.length;
}
If you can use ES6 Sets, it simply becomes:
function containsDuplicates(array) {
return array.length !== new Set(array).size
}
With vanilla javascript:
function containsDuplicates(array) {
return array
.sort()
.some(function (item, i, items) {
return item === items[i + 1]
})
}
However, sometimes you may want to check if the items are duplicated on a certain field.
This is how I'd handle that:
containsDuplicates([{country: 'AU'}, {country: 'UK'}, {country: 'AU'}], 'country')
function containsDuplicates(array, attribute) {
return array
.map(function (item) { return item[attribute] })
.sort()
.some(function (item, i, items) {
return item === items[i + 1]
})
}
Loop stops when found first duplicate:
function has_duplicates(arr) {
var x = {}, len = arr.length;
for (var i = 0; i < len; i++) {
if (x[arr[i]]) {
return true;
}
x[arr[i]] = true;
}
return false;
}
Edit (fix 'toString' issue):
function has_duplicates(arr) {
var x = {}, len = arr.length;
for (var i = 0; i < len; i++) {
if (x[arr[i]] === true) {
return true;
}
x[arr[i]] = true;
}
return false;
}
this will correct for case has_duplicates(['toString']); etc..
var index = myArray.indexOf(strElement);
if (index < 0) {
myArray.push(strElement);
console.log("Added Into Array" + strElement);
} else {
console.log("Already Exists at " + index);
}
You can convert the array to to a Set instance, then convert to an array and check if the length is same before and after the conversion.
const hasDuplicates = (array) => {
const arr = ['test0','test2','test0'];
const uniqueItems = new Set(array);
return array.length !== uniqueItems.size();
};
console.log(`Has duplicates : ${hasDuplicates(['test0','test2','test0'])}`);
console.log(`Has duplicates : ${hasDuplicates(['test0','test2','test3'])}`);
Sorting is O(n log n) and not O(n). Building a hash map is O(n). It costs more memory than an in-place sort but you asked for the "fastest." (I'm positive this can be optimized but it is optimal up to a constant factor.)
function hasDuplicate(arr) {
var hash = {};
var hasDuplicate = false;
arr.forEach(function(val) {
if (hash[val]) {
hasDuplicate = true;
return;
}
hash[val] = true;
});
return hasDuplicate;
}
It depends on the input array size. I've done some performance tests with Node.js performance hooks and found out that for really small arrays (1,000 to 10,000 entries) Set solution might be faster. But if your array is bigger (like 100,000 elements) plain Object (i. e. hash) solution becomes faster. Here's the code so you can try it out for yourself:
const { performance } = require('perf_hooks');
function objectSolution(nums) {
let testObj = {};
for (var i = 0; i < nums.length; i++) {
let aNum = nums[i];
if (testObj[aNum]) {
return true;
} else {
testObj[aNum] = true;
}
}
return false;
}
function setSolution(nums) {
let testSet = new Set(nums);
return testSet.size !== nums.length;
}
function sortSomeSolution(nums) {
return nums
.sort()
.some(function (item, i, items) {
return item === items[i + 1]
})
}
function runTest(testFunction, testArray) {
console.log(' Running test:', testFunction.name);
let start = performance.now();
let result = testFunction(testArray);
let end = performance.now();
console.log(' Duration:', end - start, 'ms');
}
let arr = [];
let setSize = 100000;
for (var i = 0; i < setSize; i++) {
arr.push(i);
}
console.log('Set size:', setSize);
runTest(objectSolution, arr);
runTest(setSolution, arr);
runTest(sortSomeSolution, arr);
On my Lenovo IdeaPad with i3-8130U Node.js v. 16.6.2 gives me following results for the array of 1,000:
results for the array of 100,000:
Assuming all you want is to detect how many duplicates of 'test0' are in the array. I guess an easy way to do that is to use the join method to transform the array in a string, and then use the match method.
var arr= ['test0','test2','test0'];
var str = arr.join();
console.log(str) //"test0,test2,test0"
var duplicates = str.match(/test0/g);
var duplicateNumber = duplicates.length;
console.log(duplicateNumber); //2

Categories

Resources