How to add two List in Javascript - javascript

This is a question from an interview book. I'm using Javascript to build the list, but the principle is still the same with List from lisp or clojure or any language. Any answer using any kind of language is accepted.
Write a function that adds the two numbers and returns the sum as a linked list. If the sum is greater than 10, extra one digit will be carried to the tail
EXAMPLE
Input: (3 -> 1 -> 5) + (5 -> 9 -> 2)
Output: 8 -> 0 -> 8
My List Class always start with one head, then followed with next, next, next and so on
List = function(){
this.head = {
value: null,
next: null
}
}
EXAMPLE of List:
var listA = new List();
/* sample data-structure
listA = {
head:{
value: 3,
next:{
value: 1,
next: {
value: 5,
next: null
}
}
}
}
*/

This is a proposal of a possible solution for different list length.
Contains
Node object with the properties value and next.
Function setValues, which creates a new list of nodes with the given array.
Function add which takes two lists of nodes and returns a new list of nodes with the result of summing the values of the same level.
function Node(value) {
this.value = value;
this.next = undefined;
}
function setValues(a) {
return a.reduceRight(function (r, v) {
var o = new Node(v);
if (r) {
o.next = r;
}
return o;
}, undefined);
}
function add(l1, l2) {
var value = 0,
last, list;
while (l1 || l2) {
if (l1) {
value += l1.value;
l1 = l1.next;
}
if (l2) {
value += l2.value;
l2 = l2.next;
}
if (last) {
last.next = new Node(value % 10);
last = last.next;
} else {
list = new Node(value % 10);
last = list;
}
value = value / 10 | 0;
}
if (value) {
last.next = new Node(value);
}
return list;
}
var list1 = setValues([3, 1, 5]),
list2 = setValues([5, 9, 2]),
list3 = add(list1, list2);
document.write('<pre>' + JSON.stringify(list1, 0, 4) + '</pre>');
document.write('<pre>' + JSON.stringify(list2, 0, 4) + '</pre>');
document.write('<pre>' + JSON.stringify(list3, 0, 4) + '</pre>');
Bonus: Version with recursive style.
function Node(value) {
this.value = value;
this.next = undefined;
}
function setValues(a) {
var n = new Node(a.shift());
if (a.length) {
n.next = setValues(a);
}
return n;
}
function add(l1, l2, r) {
function v(o, p) { return o && o[p] || 0; }
r = (r || 0) + v(l1, 'value') + v(l2, 'value');
var n = new Node(r % 10);
l1 = v(l1, 'next');
l2 = v(l2, 'next');
r = r / 10 | 0;
if (l1 || l2 || r) {
n.next = add(l1, l2, r);
}
return n;
}
var list1 = setValues([3, 1, 5]),
list2 = setValues([5, 9, 2]),
list3 = add(list1, list2);
document.write('<pre>' + JSON.stringify(list1, 0, 4) + '</pre>');
document.write('<pre>' + JSON.stringify(list2, 0, 4) + '</pre>');
document.write('<pre>' + JSON.stringify(list3, 0, 4) + '</pre>');

Related

javascript least amount of elements from an integer array that can be used to get to a total value

please can somebody help?
If i have a total or a sum for instance 91
How can I create an array of the least amount of elements needed to get to the total value?
[50, 20, 10 , 5, 3, 2, 1] totaling this array will provide 91.
I know how to perform the opposite function using reduce or like so:
<script>
var numbers = [65, 44, 12, 4];
function getSum(total, num) {
return total + num;
}
function myFunction(item) {
document.getElementById("demo").innerHTML = numbers.reduce(getSum);
}
</script>
Greedy algorithm
Here is a solution using greedy algorithm. Note that this solution will work correctly in case when all the smaller numbers are divisors of all the bigger numbers such as in case [50, 10, 5, 1]. (see dynamic algorithm below this one for solution that can handle any input)
50 mod 10 = 0
50 mod 5 = 0
50 mod 1 = 0
10 mod 5 = 0
10 mod 1 = 0
5 mod 1 = 0
const sum = xs => xs.reduce((acc, v) => acc + v, 0);
function pickSubset(options, total, currentPick) {
if (sum(currentPick) === total) { return currentPick; }
if (options.length === 0) { return null; }
const firstVal = options[0];
let res = null;
if (sum(currentPick) + firstVal > total) {
res = pickSubset(options.slice(1), total, currentPick);
} else {
let opt1 = pickSubset(options, total, currentPick.concat(options[0]));
let opt2 = pickSubset(options.slice(1), total, currentPick.concat(options[0]));
if (opt1 && opt2) {
opt1.length < opt2.length ? res = opt1 : res = opt2
} else if (opt1) {
res = opt1;
} else {
res = opt2;
}
}
return res;
}
const total = 73;
const options = [50, 25, 10, 5, 2, 1];
console.log(pickSubset(options, total, []));
To handle unsorted input you can wrap it in another function and sort it prior to passing it to the main function.
const sum = xs => xs.reduce((acc, v) => acc + v, 0);
function pickSubset(options, total, currentPick) {
const sortedOptions = options.sort((a, b) => b - a);
function _pickSubset(options, total, currentPick) {
if (sum(currentPick) === total) { return currentPick; }
if (options.length === 0) { return null; }
const firstVal = options[0];
let res = null;
if (sum(currentPick) + firstVal > total) {
res = pickSubset(options.slice(1), total, currentPick);
} else {
let opt1 = pickSubset(options, total, currentPick.concat(options[0]));
let opt2 = pickSubset(options.slice(1), total, currentPick.concat(options[0]));
if (opt1 && opt2) {
opt1.length < opt2.length ? res = opt1 : res = opt2
} else if (opt1) {
res = opt1;
} else {
res = opt2;
}
}
return res;
}
return _pickSubset(sortedOptions, total, currentPick);
}
const total = 73;
const options = [50, 25, 10, 5, 2, 1].reverse();
console.log(pickSubset(options, total, []));
Dynamic programming (bottom-up natural ordering approach)
This solution works correctly for any type of input.
function pickSubset(options, total) {
function _pickSubset(options, change, minNums, numsUsed) {
for (let i = 0; i < change + 1; i++) {
let count = i;
let newNum = 1;
let arr = options.filter(v => v <= i);
for (let j of arr) {
if (minNums[i - j] + 1 < count) {
count = minNums[i - j] + 1;
newNum = j;
}
}
minNums[i] = count;
numsUsed[i] = newNum;
}
return minNums[change];
}
function printNums(numsUsed, change) {
const res = [];
let num = change;
while (num > 0) {
let thisNum = numsUsed[num];
res.push(thisNum);
num = num - thisNum;
}
return res;
}
const numsUsed = [];
const numsCount = [];
_pickSubset(options, total, numsCount, numsUsed);
return printNums(numsUsed, total);
}
const options = [50, 10, 5, 2, 1];
console.log(pickSubset(options, 73));
Dynamic programming (top-down memoization approach)
// helper function that generates all the possible solutions
// meaning, all the possible ways in which we can pay the provided amount
// and caches those solutions;
// returns the number of possible solutions but that is not neccessary
// in this case
const _pickSubset = (toPay, options, currentPick, cache) => {
if (toPay < 0) { return 0; }
if (toPay === 0) {
cache.add(currentPick);
return 1;
}
if (options.length === 0) { return 0; }
return _pickSubset(toPay - options[0], options, currentPick.concat(options[0]), cache)
+ _pickSubset(toPay, options.slice(1), currentPick, cache);
};
// memoize only with respect to the first two arguments - toPay, bills
// the other two are not necessary in this case
const memoizeFirstTwoArgs = fn => {
const cache = new Map();
return (...args) => {
const key = JSON.stringify(args.slice(0, 2));
if (cache.has(key)) { return cache.get(key); }
const res = fn(...args);
cache.set(key, res);
return res;
};
};
// uses memoized version of makeChange and provides cache to that function;
// after cache has been populated, by executing memoized version of makeChange,
// find the option with smallest length and return it
const pickSubset = (toPay, options) => {
const cache = new Set();
const memoizedPickSubset = memoizeFirstTwoArgs(_pickSubset);
memoizedPickSubset(toPay, options, [], cache);
let minLength = Infinity;
let resValues;
for (const value of cache) {
if (value.length < minLength) {
minLength = value.length;
resValues = value;
}
}
return resValues;
}
const options = [50, 25, 10, 5, 2, 1];
const toPay = 73;
console.log(pickSubset(toPay, options));

Sort one array according to the other array using quick sort in javascript

I want to sort a, according to ascending order of c. c gets sorted by this method, but a doesn't, a has only four unsorted elements at the end of code. What changes should I make?
var a = ['e','b','d','a','f','g','c'];
function quick_Sort(origArray,a) {
var i;
var length = origArray.length;
if (origArray.length <= 1) {
return [origArray, a];
} else {
var left = [];
var right = [];
var left1 = [];
var right1 = [];
var newArray = [];
var newArray1 = [];
var pivot = origArray.pop();
var pivot1 = a.pop();
for (i = 0; i < length-1; i++) {
if (origArray[i] <= pivot) {
left.push(origArray[i]);
left1.push(a[i]);
} else {
right.push(origArray[i]);
right1.push(a[i]);
}
}
return [newArray.concat((quick_Sort(left, left1)[0]), pivot, (quick_Sort(right, right1)[0])),newArray1.concat((quick_Sort(left, left1)[1]), pivot1, (quick_Sort(right, right1)[1]))];
}
}
var c = [3, 0, 2, 5, -1, 4, 1 ];
console.log("Original array: " + c);
console.log("Original array: " + a);
var e = quick_Sort(c,a);
c = e[0];
a = e[1];
console.log("Sorted array: " + c);
console.log("Sorted array: " + a);
If you want to sort a from the corresponding value of c you can:
var a = ['e','b','d','a','f','g','c'];
var c = [3, 0, 2, 5, -1, 4, 1 ];
var [sortedA, sortedC] = a.map((v,i) => [ v, c[i] ] ) //Pair the a and c
.sort((x,y)=>x[1] - y[1]) //Sort the array based on the c value
.reduce((c,v) => {
c[0].push( v[0] );
c[1].push( v[1] );
return c;
}, [[],[]]); //Seperate the a and c
console.log( sortedA );
console.log( sortedC );

Target specific attributes with merge sort

Implemented the merge sort algorithm in my javascript code.
I'm wonder how I can target specific attributes like date, title, name etc for sorting in an array when calling merge sort like mergeSort(array);.
function mergeSort(arr){
var len = arr.length;
if(len <2)
return arr;
var mid = Math.floor(len/2),
left = arr.slice(0,mid),
right =arr.slice(mid);
return merge(mergeSort(left),mergeSort(right));
}
function merge(left, right){
var result = [],
lLen = left.length,
rLen = right.length,
l = 0,
r = 0;
while(l < lLen && r < rLen){
if(left[l] < right[r]){
result.push(left[l++]);
}
else{
result.push(right[r++]);
}
}
return result.concat(left.slice(l)).concat(right.slice(r));
}
Using it in a sort options method. What I want is to print a sorted list. The way the list is sorted will be defined by the users chosen sort option.
function sortConfig(array, sortOption){
if(sortOption == 'title') mergeSort(array.Title);
//..etc
}
To implement the behavior with an optional argument, you could do it in the following way:
function mergeSort(arr, compare = (item => item))
This would set compare function to be the item itself when running the merge
and then we update the calling of the merge and mergeSort itself, where they now all get the compare argument
return merge(mergeSort(left, compare), mergeSort(right, compare), compare);
and ofcourse the declaration for your merge function itself
function merge(left, right, compare)
Which then calls the compare function upon comparison, like here:
if (compare(left[l]) < compare(right[r]))
This lets you choose wether you wish to give an argument or not wen you call your mergeSort function, like:
console.log(mergeSort(nrs).join(','));
console.log(mergeSort(nrs, n => -n).join(','));
console.log(mergeSort(arr, i => i.id));
console.log(mergeSort(arr, i => i.title));
function mergeSort(arr, compare = (item => item)) {
var len = arr.length;
if (len < 2)
return arr;
var mid = Math.floor(len / 2),
left = arr.slice(0, mid),
right = arr.slice(mid);
return merge(mergeSort(left, compare), mergeSort(right, compare), compare);
}
function merge(left, right, compare) {
var result = [],
lLen = left.length,
rLen = right.length,
l = 0,
r = 0;
while (l < lLen && r < rLen) {
if (compare(left[l]) < compare(right[r])) {
result.push(left[l++]);
} else {
result.push(right[r++]);
}
}
return result.concat(left.slice(l)).concat(right.slice(r));
}
var arr = [{
title: 'test 5',
id: 4
}, {
title: 'test',
id: 0
}, {
title: 'test 3',
id: 2
}, {
title: 'test 4',
id: 3
}];
var nrs = [5, 3, 7, 156, 15, 6, 17, 9];
// and call like
console.log(mergeSort(nrs).join(','));
console.log(mergeSort(nrs, n => -n).join(','));
// or like
console.log(mergeSort(arr, i => i.id));
console.log(mergeSort(arr, i => i.title));
For the sake of brevity, these examples show how to sort an array of objects based on a property with a string value. You would most likely need to create some additional logic to handle different types of properties.
1. Array.sort()
You can do this with the Array.sort() method
Fiddle Example
myThings = [
{ alpha: 'a' },
{ alpha: 'x' },
{ alpha: 'p' },
{ alpha: 'orange' },
{ alpha: 'c' },
{ alpha: 'w' }
];
myThings.sort(function(a, b) {
var alphaA = a.alpha.toUpperCase();
var alphaB = b.alpha.toUpperCase();
if (alphaA < alphaB) return -1;
if (alphaA > alphaB) return 1;
return 0;
});
console.log(myThings);
2. Or, compare array item property value instead of array item value
Fiddle Example
function mergeSort(arr, prop) {
if (arr.length < 2)
return arr;
var middle = parseInt(arr.length / 2);
var left = arr.slice(0, middle);
var right = arr.slice(middle, arr.length);
return merge(mergeSort(left, prop), mergeSort(right, prop), prop);
}
function merge(left, right, prop) {
var result = [];
while (left.length && right.length) {
if (left[0][prop] <= right[0][prop]) {
result.push(left.shift());
} else {
result.push(right.shift());
}
}
while (left.length)
result.push(left.shift());
while (right.length)
result.push(right.shift());
return result;
}
myThings = [
{ alpha: 'a' },
{ alpha: 'x' },
{ alpha: 'p' },
{ alpha: 'orange' },
{ alpha: 'c' },
{ alpha: 'w' }
];
console.log(mergeSort(myThings, 'alpha'));

Sorting automobiles by multiple criteria

I have a function that is supposed to be able to compare automobiles based on year, type, make etc, but I'm having trouble getting it to work.
I define my automobiles like this:
function Automobile( year, make, model, type ){
this.year = year; //integer (ex. 2001, 1995)
this.make = make; //string (ex. Honda, Ford)
this.model = model; //string (ex. Accord, Focus)
this.type = type; //string (ex. Pickup, SUV)
}
var automobiles = [
new Automobile(1995, "Honda", "Accord", "Sedan"),
new Automobile(1990, "Ford", "F-150", "Pickup"),
new Automobile(2000, "GMC", "Tahoe", "SUV"),
new Automobile(2010, "Toyota", "Tacoma", "Pickup"),
new Automobile(2005, "Lotus", "Elise", "Roadster"),
new Automobile(2008, "Subaru", "Outback", "Wagon")
];
The above part has no issues, but my sorting function has some problems, and I can't figure out what they are. Running this code gives me the error:
Uncaught SyntaxError: Unexpected end of input
/*This function sorts arrays using an arbitrary comparator. You pass it a comparator and an array of objects appropriate for that comparator and it will return a new array which is sorted with the largest object in index 0 and the smallest in the last index*/
function sortArr( comparator, array ){
var sorted = array;
var min; var temp;
for(var i = 0; i < array.length-1; i++){
min = i;
for(var j = i+1; j < array.length; j++){
var comp = comparator(array[j], array[min]);
if(comp)
min = j;
}
if(min != i){
temp = sorted[i];
sorted[i] = sorted[min];
sorted[min] = temp;
}
}
return sorted;
}
function exComparator( int1, int2){
if (int1 > int2){
return true;
} else {
return false;
}
}
/*For all comparators if cars are 'tied' according to the comparison rules then the order of those 'tied' cars is not specified and either can come first*/
/*This compares two automobiles based on their year. Newer cars are "greater" than older cars.*/
function yearComparator( auto1, auto2){
return exComparator(auto1.make, auto2.make);
}
/*This compares two automobiles based on their make. It should be case insensitive and makes which are alphabetically earlier in the alphabet are "greater" than ones that come later.*/
function makeComparator( auto1, auto2){
return exComparator(auto1.make, auto2.make);
}
/*This compares two automobiles based on their type. The ordering from "greatest" to "least" is as follows: roadster, pickup, suv, wagon, (types not otherwise listed). It should be case insensitive. If two cars are of equal type then the newest one by model year should be considered "greater".*/
function typeComparator( auto1, auto2){
var auto1_type = switch(auto1.type.toLowerCase()){
case("roadster"): return 5;
case("pickup"): return 4;
case("suv"): return 3;
case("wagon"): return 2;
case("sedan"): return 1;
}
var auto2_type = switch(auto2.type.toLowerCase()){
case("roadster"): return 5;
case("pickup"): return 4;
case("suv"): return 3;
case("wagon"): return 2;
case("sedan"): return 1;
}
if(auto1_type > auto2_type) {
return auto1.type;
}
else if(auto2_type > auto1_type) {
return auto2.type;
}
else {
if(auto1.year > auto2.year) {
return auto1.type;
}
else {
return auto2.type;
}
}
}
function printArr(array){
for(var i = 0; i < array.length; i++){
var car = array[i];
console.log(car.year + ' ' + car.make + ' ' + car.model + ' ' + car.type);
}
}
Just some examples for sorting callbacks without switch, but with an hash table instead.
function Automobile(year, make, model, type) {
this.year = year; //integer (ex. 2001, 1995)
this.make = make; //string (ex. Honda, Ford)
this.model = model; //string (ex. Accord, Focus)
this.type = type; //string (ex. Pickup, SUV)
}
function yearComparator(a, b) {
return a.year - b.year;
}
function makeComparator(a, b) {
return a.make.localeCompare(b.make);
}
function modelComparator(a, b) {
return a.model.localeCompare(b.model);
}
function typeComparator(a, b) {
var types = { roadster: 5, pickup: 4, suv: 3, wagon: 2, sedan: 1 },
aa = types[a.type.toLowerCase()] || 0,
bb = types[b.type.toLowerCase()] || 0;
return aa - bb;
}
var automobiles = [new Automobile(1995, "Honda", "Accord", "Sedan"), new Automobile(1990, "Ford", "F-150", "Pickup"), new Automobile(2000, "GMC", "Tahoe", "SUV"), new Automobile(2010, "Toyota", "Tacoma", "Pickup"), new Automobile(2005, "Lotus", "Elise", "Roadster"), new Automobile(2008, "Subaru", "Outback", "Wagon")];
automobiles.sort(yearComparator);
document.write('<pre>sorted by year: ' + JSON.stringify(automobiles, 0, 4) + '</pre>');
automobiles.sort(makeComparator);
document.write('<pre>sorted by make: ' + JSON.stringify(automobiles, 0, 4) + '</pre>');
automobiles.sort(modelComparator);
document.write('<pre>sorted by model: ' + JSON.stringify(automobiles, 0, 4) + '</pre>');
automobiles.sort(typeComparator);
document.write('<pre>sorted by type: ' + JSON.stringify(automobiles, 0, 4) + '</pre>');
// bonus chained sort callbacks, get sorted by type DESC and year DESC
automobiles.sort(function (a, b) {
return -typeComparator(a, b) || -yearComparator(a, b);
});
document.write('<pre>sorted by type DESC and year DESC: ' + JSON.stringify(automobiles, 0, 4) + '</pre>');
You forget a curly brace { in the if statement
if (comp) <-- here
min = j;
}
Also you have wrong switch statement, you are trying assign the value from return statement
var auto1_type =
switch (auto1.type.toLowerCase()) {
case "roadster":
return 5;
...
Your switch statement should look like this
var auto1_type;
switch (auto1.type.toLowerCase()) {
case "roadster":
auto1_type = 5;
case ....
return auto1_type;

Shortest path algorithm js error

I am quite new into JS and a friend of mine sent me this fiddle
function shortestPath(g, s) {
g.vertexes.forEach(function(u) {
u.dist = Infinity;
u.prev = null;
});
s.dist = 0;
for (var i = 0; i < g.vertexes.length - 1; i++) {
g.edges.forEach(function(e) {
update(e);
});
}
printResult(); }
function update(e) {
var u = e.from;
var v = e.to;
if (v.dist > u.dist + e.data) {
v.dist = u.dist + e.data;
v.prev = u;
} }
var result = [];
function printResult() {
var str = '';
debugger;
for (var i = 0; i < result[0].length; i++) {
for (var j = 0; j < result.length; j++) {
str += result[i][j] + ' ';
}
console.log(str);
str = '';
} }
function printGraph(G) {
var a = [];
G.vertexes.forEach(function(u) {
a.push(u.dist);
});
result.push(a); }
function Graph(options) {
options = options || {};
this.directed = (options.directed != null) ? options.directed : true;
this.vertexes = [];
this.edges = []; }
Graph.prototype.vertex = function(name) {
var v = {
adjacent: [],
name: name.toString()
};
this.vertexes.push(v);
return this; };
Graph.prototype.get = function(name) {
return this.vertexes.filter(function(el) {
return el.name === name.toString();
})[0]; };
Graph.prototype.edge = function(a, b, w) {
var that = this;
connect(a, b, w);
if (!this.directed) {
connect(b, a, w);
}
function connect(a, b, data) {
var u = that.vertexes.filter(function(el) {
return el.name === a.toString();
})[0];
var v = that.vertexes.filter(function(el) {
return el.name === b.toString();
})[0];
u.adjacent.push(v);
that.edges.push({
from: u,
to: v,
data: data
});
}
return this; };
function main() {
var g = new Graph();
g.vertex(1)
.vertex(2)
.vertex(3)
.vertex(4)
.vertex(5)
.vertex(6)
.vertex(7)
.vertex(8);
g.edge(1, 2, -2);
g.edge(1, 5, -2);
g.edge(1, 6, -3);
g.edge(1, 8, -1);
g.edge(2, 6, 7);
g.edge(2, 8, 4);
g.edge(3, 2, 2);
g.edge(3, 4, 5);
g.edge(3, 7, 9);
g.edge(4, 7, 4);
g.edge(5, 7, 5);
g.edge(7, 8, -1);
g.edge(8, 2, 2);
g.edge(8, 5, 8);
g.edge(8, 6, 3);
g.edge(8, 7, 7);
shortestPath(g, g.get(3));
console.log(g); }
main();
(Shortest path Bellman-Ford)
and don't really get it why it throws the error property 'length' of undefined in the console.
Any advice how to fix this error?
In general, when JS complains Cannot read property "xxx" of undefined, that means that somewhere you have foo.xxx and foo is the JavaScript value undefined (which is not an object, and has no properties).
Track such a problem down by finding the line in question (using debugging tools, or even just looking for .length in your case) and considering: when might the variable in question be undefined?
In your specific case, the error occurs on this line:
for (var i = 0; i < result[0].length; i++) {
which means that result[0] is undefined. Which means that your result array has no value at [0]. It is empty.
Since the printResult function is called from one place (line 59), this likely means that result is still an empty array when printResult() is called. You can confirm this by setting a breakpoint at that location and examining what result is.
As for why it is empty:
The only code that affects the result array is result.push(a) in the printGraph() function. And this function is never called. Ask your friend why s/he defined printGraph() but never invoked it.
It may be as simple as calling printGraph(g) right before printResult().

Categories