Find an nth element from the end of an array - javascript

i looked at this challenge from codesignal (nthelementfromtheend) and put my code (below) in a test site
function nthElementFromTheEnd(l, n) {
if (n > l.length){
return -1;
}else{
// console.log();
let index = l.length - n;
// console.log(index);
// console.log(l[index]);
return l[index];
}
}
let l = [1, 2, 3, 4];
let n=7;
nthElementFromTheEnd(l, n);
results seem to pass the test site, but not codesignal.
open links below in new tab
challenge
tester
array length

You need to analyze the input that is coming into the function. l represents a singly-linked list. This doesn't exist natively in JavaScript, but it has been re-created using an object, as the comment describes:
// Singly-linked lists are already defined with this interface:
function ListNode(x) {
this.value = x;
this.next = null;
}
In the first test, the input that comes to the function looks like this:
ListNode {
value: 1,
next: ListNode {
value: 2,
next: ListNode {
value: 3,
next: null
}
}
}
So this is not as simple as returning a particular index from an array, because the function is not receiving an array but an object. You have to navigate the data structure continually checking for next values. There are probably more efficient ways to do this, but here's an example that at least passes the 8 sample tests:
function nthElementFromTheEnd(l, n) {
let values = [];
let node = l;
while (node) {
values.push(node.value);
node = node.next;
}
let len = values.length;
if (n > len) {
return -1;
} else {
return values[len-n];
}
}

The trick here is in the comment indicating the interface of a singly-linked lists.
// Singly-linked lists are already defined with this interface:
// function ListNode(x) {
// this.value = x;
// this.next = null;
// }
//
So you need to use l.next and l.value to navigate and get values from the linked list.
Here is a possible solution (not optimized):
function nthElementFromTheEnd(l, n) {
// find the length of the linked list
let len = 1;
let c = l;
while (c.next) {
len++;
c = c.next;
}
if (n > len) {
return -1
}
else {
// iterate linked list and get desired value (len-n)
let i = 0;
while (i < len-n){
l = l.next;
i++;
}
return l.value;
}
}

function nthElementFromTheEnd(l, n) {
var input = l;
var rev= input.reverse();
let value = rev[n-1];
if(value){
return value;
}
else
return -1;
}

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);

Nesting dot notation within bracket notation to create nested objects

"Write a function arrayToList that builds up a list structure like"
let LL = { data: 1, next: { data: 2, next: { data: 3, next: null }}};
I understand the typical solution to this problem, where the list must be built from the inside out:
function arrToLList(arr) {
let LList = null;
for (let i = arr.length - 1; i >= 0; i--) {
LList = { data: arr[i], next: LList };
}
return LList;
}
But my initial solution was to brute force it with a typical for loop.
function arrayToLList(arr) {
let d = "data";
let n = "next";
let LList = nextNode();
for (let i = 0; i < arr.length; i++) {
LList[d] = arr[i];
d = "next." + d;
LList[n] = nextNode();
n = "next." + n;
}
function nextNode() {
return {
data: null,
next: null
};
}
return LList;
}
What you want to achieve is possible, but you need to customize the functionality of how getting a property works when you use bracket notation. As you mentioned, using dot notation with bracket notation won't work, you need a way to define this logic yourself. ES6 introduced Proxies which allows you to specify a set method trap for your object. Whenever you set a value on the object, the set method will be called. Using this idea, you can split the dot-notation string by . and traverse the path it returns to get your nested object. Once you have retrieved the nested object, you can set its value.
See example below:
function arrayToLList(arr) {
let d = "data";
let n = "next";
let LList = nextNode();
for (let i = 0; i < arr.length; i++) {
LList[d] = arr[i];
d = "next." + d;
if(i < arr.length-1) // don't add null object to last node
LList[n] = nextNode();
n = "next." + n;
}
function nextNode() {
const obj = {
data: null,
next: null
};
return new Proxy(obj, {
set: function(obj, key, val) {
const path = key.split('.');
const last = path.pop();
for(const prop of path)
obj = obj[prop];
obj[last] = val;
return true;
}
});
}
return LList;
}
console.log(arrayToLList([1, 2, 3]));
However, you don't need to use a proxy. A more straightforward way of doing this would be by creating a method such as setValueByPath(val, obj, strPath) which performs the logic in the proxy for you. Then, instead of setting your object using bracket notation, you simply call the setValueByPath(obj, strPath):
function setValudByPath(val, obj, strPath) { // pefroms same logic from proxy, just using reduce instead
const path = strPath.split('.');
const last = path.pop();
path.reduce((nested, p) => nested[p], obj)[last] = val;
}
function arrayToLList(arr) {
let d = "data";
let n = "next";
let LList = {data: null, next: null};
for (let i = 0; i < arr.length; i++) {
setValudByPath(arr[i], LList, d); // same as LList[d] = arr[i];
d = "next." + d;
if(i < arr.length-1) // don't add null object to last node
setValudByPath({data: null, next: null}, LList, n); // same as: LList[n] = nextNode();
n = "next." + n;
}
return LList;
}
console.log(arrayToLList([1, 2, 3]));
As you are trying to access an objects parameters using strings.
You can't use dot notation with string.
e.g.
let data = {name:'test'};
console.log("data.name");
this is what you're attempting and it will return data.name and not the value test.
you can do the following though: data['name'] so with nested object you can do the following:
LList['next']['next']...['next']['data']
to get the n'th data element.

return object if list<object> value is exists (Javascript, jquery grep/map)

I'm using grep and map functions to get the object if the value is exists in the list, but it does not work well.
I have a list customList and the customObject has the int id property and List value properties.
customobject[0].id
customObject[0].value[]
What I want is check if in the List the value 5 exists.
The function what I'm using is:
var gettedcustomObject = $.grep(customList, function (e) {
var result = e.Value.map(function (a) { return a === 5;});
return result;
});
What am I doing wrong and what is the correct implementation?
Note: 2x foreach could be a solution, but customList has more than 1000 objects with 10000 values. I think that slow down the proces.
This should do it.
var gettedcustomObject = customList.filter(function(v){
var ln = v.Value.length;
for(var i = 0; i < ln; i++){
if(v.Value[i] == 5){
return true;
}
}
return false;
// Or simply:
// return v.Value.indexOf(5) != -1;
});
This will work if v.Value is an array.
You should look at some: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some#Polyfill
Way faster than the other methods like filter, map or sort as it was designed for this.
//List to work against
var arr = [];
//Populate
while (arr.length < 9999999) {
arr.push(Math.random() * 999999)
}
//Set element to find
arr[10] = "test";
//Begin timing
var d = new Date().getTime();
//Run filter
console.log(arr.filter(function(a){return a === "test"}).length > 0);
//How long did it take
console.log("`filter` took:",new Date().getTime() - d,"ms")
//Begin timing
d = new Date().getTime();
//Run filter
console.log(arr.some(function(a){return a === "test"}));
//How long did it take
console.log("`some` took:",new Date().getTime() - d,"ms")
<script>
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some#Polyfill
// Production steps of ECMA-262, Edition 5, 15.4.4.17
// Reference: http://es5.github.io/#x15.4.4.17
if (!Array.prototype.some) {
Array.prototype.some = function(fun/*, thisArg*/) {
'use strict';
if (this == null) {
throw new TypeError('Array.prototype.some called on null or undefined');
}
if (typeof fun !== 'function') {
throw new TypeError();
}
var t = Object(this);
var len = t.length >>> 0;
var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
for (var i = 0; i < len; i++) {
if (i in t && fun.call(thisArg, t[i], i, t)) {
return true;
}
}
return false;
};
}
</script>
If your goal is to find the first object in the list that contains 5 in the Value property, then you're looking for Array#find and Array#indexOf:
var gettedcustomObject = customList.find(function(entry) {
return entry.Value.indexOf(5) != -1;
});
Note that Array#find was added relatively recently and so you may need a polyfill for it (which is trivial). MDN has one.
Or you could use Array#includes instead of indexOf, which will be in ES2017 and is also polyfillable:
var gettedcustomObject = customList.find(function(entry) {
return entry.Value.includes(5);
});
Live Example (using indexOf):
var customList = [
{
note: "I'm not a match",
Value: [2, 3, 4]
},
{
note: "I'm not a match either",
Value: [78, 4, 27]
},
{
note: "I'm a match",
Value: [889, 5, 27]
},
{
note: "I'm also a match, but you won't find me",
Value: [4, 6, 5]
}
];
var gettedcustomObject = customList.find(function(entry) {
return entry.Value.indexOf(5) != -1;
});
console.log(gettedcustomObject);
If your logic matching the item inside Value were more complicated, you'd use Array#some and a callback function rathe than indexOf. But when looking to see if an array for an entry in an array based on ===, indexOf or the new Array#includes are the way to go.
one approach using Array.some() and Array.indexOf(). some loop break once the element is found
var gettedcustomObject;
customobject.some(function(obj){
if(obj.value.indexOf(5) >-1){
gettedcustomObject = obj;
return true;
}
});

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.

Cycle function in Javascript

I new to Javascript and I am looking for a cycle function. Here's Clojure's implementation I am trying to find a cycle function that infinitely loops/recurses through values of an array. I was hoping to find something like this in the underscore library, but I could not find anything suitable. Ideally I would like to use something like this:
_.head(_.cycle([1,2,3]), 100)
This function would return an array of 100 elements:
[1,2,3,1,2,3,1,2,3,1,2,3,...]
Is there a function like this I can use in Javascript? Here's my feable attempt, but I can't seem to get it to work:
arr = [1,2,3,4,5,6,7,8,9];
var cycle = function(arr) {
arr.forEach(function(d, i) {
if (d === arr.length)
return d
d == 0
else {return d}
});
};
cycle(arr);
You could do something like:
var cycle = function(array, count) {
var output = [];
for (var i = 0; i < count; i++) {
output.push(array[i % array.length]);
}
return output;
}
An implementation of Clojure's cycle :
function cycle(input) {
return function (times) {
var i = 0, output = [];
while (i < times) {
output.push(input[i++ % input.length]);
}
return output;
};
}
Usage examples :
var chars = cycle(['a', 'b']);
chars(0) // []
chars(1) // ["a"]
chars(3) // ["a", "b", "a"]
cycle([1, 2])(3) // [1, 2, 1]
An implementation of Clojure's take :
function take(length, input) {
return typeof input === 'function'
? input(length)
: input.slice(0, length);
}
Usage examples :
take(3, [1, 2, 3, 4]) // [1, 2, 3]
take(3, cycle([1, 2])) // [1, 2, 1]
Both implementations probably do not fit exactly Clojure's versions.
The problem with trying to emulate purely functional in JavaScript is eagerness: JavaScript doesn't have lazy evaluation and hence you can't produce infinite arrays in JavaScript. You need to define a lazy list in JavaScript. This is how I usually do it:
function cons(head, tail) {
return cont({
head: head,
tail: tail
});
}
function cont(a) {
return function (k) {
return k(a);
};
}
The cons function is similar to the cons function in LISP or the : constructor in Haskell. It takes an element and a list and returns a new list with the element inserted at the beginning of the list. The cont function creates a continuation (really useful for reifying thunks to emulate lazy evaluation).
Creating a list using cons is very simple:
var list = cons(1, cons(2, cons(3, cons(4, cons(5, null)))));
var array = [1, 2, 3, 4, 5];
The above list and array are equivalent. We can create two function to convert arrays to lists and vice-versa:
function toList(array) {
var list = null, length = array.length;
while (length) list = cons(array[--length], list);
return list;
}
function toArray(list) {
var array = [];
while (list) {
list = list(id);
array = array.concat(list.head);
list = list.tail;
}
return array;
}
function id(x) {
return x;
}
Now that we have a method of implementing lazy lists in JavaScript let's create the cycle function:
function cycle(list) {
list = list(id);
var head = list.head;
var tail = join(list.tail, cons(head, null));
return function (k) {
return k({
head: head,
tail: cycle(tail)
});
};
}
function join(xs, ys) {
if (xs) {
xs = xs(id);
return cons(xs.head, join(xs.tail, ys));
} else return ys;
}
Now you can create an infinite list as follows:
var list = cycle(toList([1,2,3]));
Let's create a take function to get the first 100 elements of the list:
function take(n, xs) {
if (n > 0) {
xs = xs(id);
return cons(xs.head, take(n - 1, xs.tail));
} else return null;
}
We can now easily get an array of 100 elements with [1,2,3] repeating:
var array = toArray(take(100, list));
Let's see if it works as expected: http://jsfiddle.net/TR9Ma/
To summarize, lazy functional programming in JavaScript is not as much fun as it is in purely functional languages like Haskell. However with a little bit of effort you can make it work.
Here is a slightly more compact version:
function cycle(arr, count) {
for (var i = 0, out = []; i < count; i++) {
out.push(arr[i % arr.length]);
}
return out;
}
And a JSFiddle (outputs the results to the console):
http://jsfiddle.net/2F9hY/1/
Basically just loops through count number of times, getting the i % arr.length item and adding it to the array.
This function should work. You can put the mod operation to good use here.
var cycle = function(input, n) {
var output = [];
for (var i = 0; i < n; i++) {
var j = i % input.length;
output.push(input[j]);
}
return output;
}
Here's a working fiddle: http://jsfiddle.net/K6UhS/1/
Also, I wouldn't introduce a whole library just for this function!
The wu library includes a cycle function which does this:
wu.cycle([ 1, 2, 3 ]).take(10).toArray() // [ 1, 2, 3, 1, 2, 3, 1, 2, 3, 1 ]
If you don't need support for iterators/streams/infinite lists, and just want a function that cycles through an array's values, lei-cycle provides a much more lightweight solution:
const Cycle = require('lei-cycle')
let c = Cycle([ 1, 2, 3 ])
console.log(c()) // 1
console.log(c()) // 2
console.log(c()) // 3
console.log(c()) // 1
// ...
function cycle(array) {
let result = [...array]
result[Symbol.iterator] = function* () {
while (true)
yield* this.values()
}
return result
}
class Cycle {
constructor(array) {
this.array = array;
}
next () {
var x = this.array.shift();
this.array.push(x);
return x;
}
}
const cycle = new Cycle(['a','b','c']);
console.log(cycle.next()); // returns "a"
console.log(cycle.next()); // returns "b"
console.log(cycle.next()); // returns "c"
console.log(cycle.next()); // returns "a"
console.log(cycle.next()); // returns "b"
...

Categories

Resources