Related
I'm doing a kata on Codewars. I'm supposed to write a function that returns the index of which number, is not like the others, in evenness(i.e. [1, 2, 4] should return 0). I believe I have a solution, and it proves true when copy/pasting the code, and console.logging on freecodecamps live server, however, when i try to run the code where it is written, it only passes one test. What is going wrong here?
I've tried testing with console.logs, and my solution holds. I know I could just use filter to solve the problem, but i wan't to practice fundamentals.
let odd = [];
let even = [];
function isEven(num) {
if (num % 2 === 0) {
return true;
} else {
return false;
}
}
function iqTest(numbers) {
let nums = numbers.split(' ').map(function(item) {
return parseInt(item, 10);
})
for (let i in nums) {
if (isEven(nums[i])) {
even.push(nums[i])
} else {
odd.push(nums[i])
}
}
if (even.length > odd.length) {
return nums.indexOf(odd[0]) + 1;
} else {
return nums.indexOf(even[0]) + 1;
}
}
The function should accept a string of numbers, one of which will not be either even or odd, then return the index of that number + 1.
You could take the in comments mentioned approach and search for at least one odd and one even and one additional item, at least three items and exit early if this combination is found.
No need to convert the values in advance, because the value get converted to number by using the remainder operator of isEven function.
For a faster return value store the index instead of the value and omit a later indexOf seach.
function isEven(i) { return i % 2 === 0; }
function iqTest(numbers) {
var even = [], odd = [], values = numbers.split(' ');
for (let i = 0; i < values.length; i++) {
(isEven(values[i]) ? even : odd).push(i);
if (even.length && odd.length && even.length + odd.length > 2)
return (even.length < odd.length ? even : odd)[0] + 1;
}
}
console.log(iqTest("1 2 4")); // 1
console.log(iqTest("2 4 7 8 10")) // 3
console.log(iqTest("1 2 1 1")); // 2
Suppose we have the elements 0 and 1, which can occour more than once, something like 00 00 11, 00 00 11 11 or 01 11 (split into groups of 2 for better readability).
I've already a function to generate all unique permutations:
class UniqueElement {
constructor(value, occurrences) {
this.value = value;
this.occurrences = occurrences;
}
}
function permUnique(elements) {
let set = new Set(elements);
let listunique = Array.from(set).map((i) => new UniqueElement(i, elements.filter((el) => el === i).length));
let u = elements.length;
return permUniqueHelper(listunique, "0".repeat(u).split("").map((i) => parseInt(i)), u - 1);
}
function* permUniqueHelper(listunique, result_list, d) {
if (d < 0) {
yield [...result_list];
} else {
for (const i of listunique) {
if (i.occurrences > 0) {
result_list[d] = i.value;
i.occurrences--;
for (const g of permUniqueHelper(listunique, result_list, d - 1)) yield g;
i.occurrences++;
}
}
}
}
// call like:
// permUnique([0,0,1,1])
console.log(Array.from(permUnique([0,0,1,1])).join('\n'));
Translated into JavaScript from here: https://stackoverflow.com/a/6285203/10362619
Now my intention is to use these generated permutations as indices for other objects.
These are then used in code, where the order of these objects doesn't matter:
10 10
01 01
are the same in the end for example, or
01 20 12
02 10 21
10 21 02
12 01 20
...
for a base with 0, 1 and 2 starting from 00 11 22.
They are considered the same, because equal numbers are in the same position. Just switch two numbers (e.g. 0 with 1) and you'll get the other.
Again, all these examples are just split into groups of two for better readability. 00 11 22 means the same as 001122, where each digit is a single element in the input array.
Is the fastest way to filter the elements afterwards after the permutations have been created or can this criteria be implemented in the function?
Edit: It is no requirement that it is a generator function that permutes the array
Edit 2: To make things even more clear: The first example I gave has the pattern abab where a can be either 0 or 1 and b is the opposite. The second example follows the pattern abcabc where a, b and c can all be either 0, 1 or 2 (but not the same).
After having an equality criteria between the different permutations, we need to establish a canonical form for each pattern (equality class). We will then try to only generate those.
In your case, where order of 1s, 2s and 3s does not matter, we could decide that their respective first occurrences must be in the order 123, and 2 cannot appear without 1 and 3 not without 2. So whether the pattern is aabcbc, aacbcb, bbacac, …, or ccbaba, the only form that we want to generate is 112323. Or when the pattern is aaa/bbb/ccc we only generate 111 but not 222 or 333.
We can then write an algorithm which follows these rules for canonical forms:
function patterns(values, len) {
function* recurse(list, used, depth) {
if (depth == len) {
yield list.slice();
} else {
for (let j=0; j<used; j++) { // only put already used values at this position
list[depth] = values[j];
yield* recurse(list, used, depth+1);
}
if (used < values.length) { // or the single next unused value
list[depth] = values[used];
yield* recurse(list, used+1, depth+1); // which is counted as used here
}
}
}
return recurse([], 0, 0);
}
This simply generates all combinations of a certain length from the distinct values, but you can use the same approach in your algorithm that generates permutations from a certain amount of non-unique values. It does get a bit more complicated though: the canonical form 121 cannot be achieved if we only have the values 122 available, but the pattern 212 still should be generated. We need to adjust our rule so that the ordering requirement is only amongst elements of the same number of occurrences. So we have to keep different used counts for them.
function permutationPatterns(elements) {
const len = elements.length;
const unique = new Map(elements.map(el => [el, {value: el, occurrences: 0}]));
let max = 0;
for (const el of elements) {
const o = unique.get(el);
max = Math.max(max, ++o.occurrences);
}
const byOccurrences = Array.from({length: max+1}, () => ({elements: [], used: 0}));
for (const o of unique.values()) {
byOccurrences[o.occurrences].elements.push(o);
}
function* generate(list, depth) {
if (depth == len) {
yield list.slice();
} else {
for (const options of byOccurrences) {
options.used++;
for (const option of options.elements.slice(0, options.used)) {
if (option.occurrences == 0) continue;
option.occurrences--;
list[depth] = option.value;
yield* generate(list, depth+1);
option.occurrences++;
}
options.used--;
}
}
}
return generate([], 0);
}
If 12 and 21 are the same, like 10 and 01 are the same after all, then don't create all of them in the first place. The key idea here is to have a canonical form for each of the values, which could e.g. be that the digits are sorted ascending. So you'd only have the values 00, 01, 02, 11, 12 and 22.
If the order in the sequence doesn't matter either, then you shouldn't be generating permutations. Again, choose a canonical form for the sequences.
You can then easily generate only ascending forms, and use the same generator once for your parts and once for the whole sequence:
function* generate(values, len) {
if (len == 0)
yield [];
else
for (const [i, val] of values.entries())
for (const rest of generate(values.slice(i), len-1))
yield [val, ...rest];
}
const duos = Array.from(generate([0, 1, 2], 2), x => x.join(""));
for (const x of generate(duos, 3))
console.log(x.join(" "))
I've now wrapped the generator function inside a filter generator function as #PatrickRoberts suggested in the comments of the question.
class UniqueElement {
constructor(value, occurrences) {
this.value = value;
this.occurrences = occurrences;
}
}
function uniquePermutations(elements) {
let set = new Set(elements);
let listunique = Array.from(set).map((i) => new UniqueElement(i, elements.filter((el) => el === i).length));
let u = elements.length;
return uniquePermutationsHelper(listunique, "0".repeat(u).split("").map((i) => parseInt(i)), u - 1);
}
function* uniquePermutationsHelper(listunique, result_list, d) {
if (d < 0) {
yield [...result_list];
} else {
for (const i of listunique) {
if (i.occurrences > 0) {
result_list[d] = i.value;
i.occurrences--;
for (const g of uniquePermutationsHelper(listunique, result_list, d - 1)) yield g;
i.occurrences++;
}
}
}
}
function* uniquePermutationPatterns(elements) {
let patterns = [];
for (const perm of uniquePermutations(elements)) {
// contains all unique elements in the order they appear. call patternVars.indexOf(element) and use its index for the patterns array
let patternVars = Array.from(new Set(perm));
let pattern = perm.map((p) => patternVars.indexOf(p));
// convert the pattern to a number to avoid comparing array references and use the faster number comparison than the slower string comparison
pattern = parseInt(pattern.join(""), patternVars.length);
if (!patterns.length || !patterns.includes(pattern)) {
patterns.push(pattern);
yield perm;
}
}
}
let elements = [0,0,1,1];
let all = [...uniquePermutations(elements)];
let filtered = [...uniquePermutationPatterns(elements)];
console.log(`all permutations: (${all.length})`);
console.log(all.map((i) => i.join("")).join("\n"));
console.log(`\nfiltered permutations: (${filtered.length})`);
console.log(filtered.map((i) => i.join("")).join("\n"));
But that is about 3.2 times slower than simply generating all permutations. Which doesn't matter in my case. I only tested the performance for the array of elements [0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2] and that only a few times (less than 10)
I want to know the size occupied by a JavaScript object.
Take the following function:
function Marks(){
this.maxMarks = 100;
}
function Student(){
this.firstName = "firstName";
this.lastName = "lastName";
this.marks = new Marks();
}
Now I instantiate the student:
var stud = new Student();
so that I can do stuff like
stud.firstName = "new Firstname";
alert(stud.firstName);
stud.marks.maxMarks = 200;
etc.
Now, the stud object will occupy some size in memory. It has some data and more objects.
How do I find out how much memory the stud object occupies? Something like a sizeof() in JavaScript? It would be really awesome if I could find it out in a single function call like sizeof(stud).
I’ve been searching the Internet for months—couldn’t find it (asked in a couple of forums—no replies).
I have re-factored the code in my original answer. I have removed the recursion and removed the assumed existence overhead.
function roughSizeOfObject( object ) {
var objectList = [];
var stack = [ object ];
var bytes = 0;
while ( stack.length ) {
var value = stack.pop();
if ( typeof value === 'boolean' ) {
bytes += 4;
}
else if ( typeof value === 'string' ) {
bytes += value.length * 2;
}
else if ( typeof value === 'number' ) {
bytes += 8;
}
else if
(
typeof value === 'object'
&& objectList.indexOf( value ) === -1
)
{
objectList.push( value );
for( var i in value ) {
stack.push( value[ i ] );
}
}
}
return bytes;
}
The Google Chrome Heap Profiler allows you to inspect object memory use.
You need to be able to locate the object in the trace which can be tricky. If you pin the object to the Window global, it is pretty easy to find from the "Containment" listing mode.
In the attached screenshot, I created an object called "testObj" on the window. I then located in the profiler (after making a recording) and it shows the full size of the object and everything in it under "retained size".
More details on the memory breakdowns.
In the above screenshot, the object shows a retained size of 60. I believe the unit is bytes here.
Sometimes I use this to flag really big objects that might be going to the client from the server. It doesn't represent the in memory footprint. It just gets you approximately what it'd cost to send it, or store it.
Also note, it's slow, dev only. But for getting an ballpark answer with one line of code it's been useful for me.
roughObjSize = JSON.stringify(bigObject).length;
I just wrote this to solve a similar (ish) problem. It doesn't exactly do what you may be looking for, ie it doesn't take into account how the interpreter stores the object.
But, if you are using V8, it should give you a fairly ok approximation as the awesome prototyping and hidden classes lick up most of the overhead.
function roughSizeOfObject( object ) {
var objectList = [];
var recurse = function( value )
{
var bytes = 0;
if ( typeof value === 'boolean' ) {
bytes = 4;
}
else if ( typeof value === 'string' ) {
bytes = value.length * 2;
}
else if ( typeof value === 'number' ) {
bytes = 8;
}
else if
(
typeof value === 'object'
&& objectList.indexOf( value ) === -1
)
{
objectList[ objectList.length ] = value;
for( i in value ) {
bytes+= 8; // an assumed existence overhead
bytes+= recurse( value[i] )
}
}
return bytes;
}
return recurse( object );
}
Here's a slightly more compact solution to the problem:
const typeSizes = {
"undefined": () => 0,
"boolean": () => 4,
"number": () => 8,
"string": item => 2 * item.length,
"object": item => !item ? 0 : Object
.keys(item)
.reduce((total, key) => sizeOf(key) + sizeOf(item[key]) + total, 0)
};
const sizeOf = value => typeSizes[typeof value](value);
There is a NPM module to get object sizeof, you can install it with npm install object-sizeof
var sizeof = require('object-sizeof');
// 2B per character, 6 chars total => 12B
console.log(sizeof({abc: 'def'}));
// 8B for Number => 8B
console.log(sizeof(12345));
var param = {
'a': 1,
'b': 2,
'c': {
'd': 4
}
};
// 4 one two-bytes char strings and 3 eighth-bytes numbers => 32B
console.log(sizeof(param));
This is a hacky method, but i tried it twice with different numbers and it seems to be consistent.
What you can do is to try and allocate a huge number of objects, like one or two million objects of the kind you want. Put the objects in an array to prevent the garbage collector from releasing them (note that this will add a slight memory overhead because of the array, but i hope this shouldn't matter and besides if you are going to worry about objects being in memory, you store them somewhere). Add an alert before and after the allocation and in each alert check how much memory the Firefox process is taking. Before you open the page with the test, make sure you have a fresh Firefox instance. Open the page, note the memory usage after the "before" alert is shown. Close the alert, wait for the memory to be allocated. Subtract the new memory from the older and divide it by the amount of allocations. Example:
function Marks()
{
this.maxMarks = 100;
}
function Student()
{
this.firstName = "firstName";
this.lastName = "lastName";
this.marks = new Marks();
}
var manyObjects = new Array();
alert('before');
for (var i=0; i<2000000; i++)
manyObjects[i] = new Student();
alert('after');
I tried this in my computer and the process had 48352K of memory when the "before" alert was shown. After the allocation, Firefox had 440236K of memory. For 2million allocations, this is about 200 bytes for each object.
I tried it again with 1million allocations and the result was similar: 196 bytes per object (i suppose the extra data in 2mill was used for Array).
So, here is a hacky method that might help you. JavaScript doesn't provide a "sizeof" method for a reason: each JavaScript implementaion is different. In Google Chrome for example the same page uses about 66 bytes for each object (judging from the task manager at least).
Having the same problem. I searched on Google and I want to share with stackoverflow community this solution.
Important:
I used the function shared by Yan Qing on github
https://gist.github.com/zensh/4975495
function memorySizeOf(obj) {
var bytes = 0;
function sizeOf(obj) {
if(obj !== null && obj !== undefined) {
switch(typeof obj) {
case 'number':
bytes += 8;
break;
case 'string':
bytes += obj.length * 2;
break;
case 'boolean':
bytes += 4;
break;
case 'object':
var objClass = Object.prototype.toString.call(obj).slice(8, -1);
if(objClass === 'Object' || objClass === 'Array') {
for(var key in obj) {
if(!obj.hasOwnProperty(key)) continue;
sizeOf(obj[key]);
}
} else bytes += obj.toString().length * 2;
break;
}
}
return bytes;
};
function formatByteSize(bytes) {
if(bytes < 1024) return bytes + " bytes";
else if(bytes < 1048576) return(bytes / 1024).toFixed(3) + " KiB";
else if(bytes < 1073741824) return(bytes / 1048576).toFixed(3) + " MiB";
else return(bytes / 1073741824).toFixed(3) + " GiB";
};
return formatByteSize(sizeOf(obj));
};
var sizeOfStudentObject = memorySizeOf({Student: {firstName: 'firstName', lastName: 'lastName', marks: 10}});
console.log(sizeOfStudentObject);
What do you think about it?
Sorry I could not comment, so I just continue the work from tomwrong.
This enhanced version will not count object more than once, thus no infinite loop.
Plus, I reckon the key of an object should be also counted, roughly.
function roughSizeOfObject( value, level ) {
if(level == undefined) level = 0;
var bytes = 0;
if ( typeof value === 'boolean' ) {
bytes = 4;
}
else if ( typeof value === 'string' ) {
bytes = value.length * 2;
}
else if ( typeof value === 'number' ) {
bytes = 8;
}
else if ( typeof value === 'object' ) {
if(value['__visited__']) return 0;
value['__visited__'] = 1;
for( i in value ) {
bytes += i.length * 2;
bytes+= 8; // an assumed existence overhead
bytes+= roughSizeOfObject( value[i], 1 )
}
}
if(level == 0){
clear__visited__(value);
}
return bytes;
}
function clear__visited__(value){
if(typeof value == 'object'){
delete value['__visited__'];
for(var i in value){
clear__visited__(value[i]);
}
}
}
roughSizeOfObject(a);
i want to know if my memory reduction efforts actually help in reducing memory
Following up on this comment, here's what you should do:
Try to produce a memory problem - Write code that creates all these objects and graudally increase the upper limit until you ran into a problem (Browser crash, Browser freeze or an Out-Of-memory error). Ideally you should repeat this experiment with different browsers and different operating system.
Now there are two options:
option 1 - You didn't succeed in producing the memory problem. Hence, you are worrying for nothing. You don't have a memory issue and your program is fine.
option 2- you did get a memory problem. Now ask yourself whether the limit at which the problem occurred is reasonable (in other words: is it likely that this amount of objects will be created at normal use of your code). If the answer is 'No' then you're fine. Otherwise you now know how many objects your code can create. Rework the algorithm such that it does not breach this limit.
This Javascript library sizeof.js does the same thing.
Include it like this
<script type="text/javascript" src="sizeof.js"></script>
The sizeof function takes an object as a parameter and returns its approximate size in bytes. For example:
// define an object
var object =
{
'boolean' : true,
'number' : 1,
'string' : 'a',
'array' : [1, 2, 3]
};
// determine the size of the object
var size = sizeof(object);
The sizeof function can handle objects that contain multiple references to other objects and recursive references.
Originally published here.
If your main concern is the memory usage of your Firefox extension, I suggest checking with Mozilla developers.
Mozilla provides on its wiki a list of tools to analyze memory leaks.
Chrome developer tools has this functionality. I found this article very helpful and does exactly what you want:
https://developers.google.com/chrome-developer-tools/docs/heap-profiling
Many thanks to everyone that has been working on code for this!
I just wanted to add that I've been looking for exactly the same thing, but in my case it's for managing a cache of processed objects to avoid having to re-parse and process objects from ajax calls that may or may not have been cached by the browser. This is especially useful for objects that require a lot of processing, usually anything that isn't in JSON format, but it can get very costly to keep these things cached in a large project or an app/extension that is left running for a long time.
Anyway, I use it for something something like:
var myCache = {
cache: {},
order: [],
size: 0,
maxSize: 2 * 1024 * 1024, // 2mb
add: function(key, object) {
// Otherwise add new object
var size = this.getObjectSize(object);
if (size > this.maxSize) return; // Can't store this object
var total = this.size + size;
// Check for existing entry, as replacing it will free up space
if (typeof(this.cache[key]) !== 'undefined') {
for (var i = 0; i < this.order.length; ++i) {
var entry = this.order[i];
if (entry.key === key) {
total -= entry.size;
this.order.splice(i, 1);
break;
}
}
}
while (total > this.maxSize) {
var entry = this.order.shift();
delete this.cache[entry.key];
total -= entry.size;
}
this.cache[key] = object;
this.order.push({ size: size, key: key });
this.size = total;
},
get: function(key) {
var value = this.cache[key];
if (typeof(value) !== 'undefined') { // Return this key for longer
for (var i = 0; i < this.order.length; ++i) {
var entry = this.order[i];
if (entry.key === key) {
this.order.splice(i, 1);
this.order.push(entry);
break;
}
}
}
return value;
},
getObjectSize: function(object) {
// Code from above estimating functions
},
};
It's a simplistic example and may have some errors, but it gives the idea, as you can use it to hold onto static objects (contents won't change) with some degree of intelligence. This can significantly cut down on any expensive processing requirements that the object had to be produced in the first place.
The accepted answer does not work with Map, Set, WeakMap and other iterable objects. (The package object-sizeof, mentioned in other answer, has the same problem).
Here's my fix
export function roughSizeOfObject(object) {
const objectList = [];
const stack = [object];
const bytes = [0];
while (stack.length) {
const value = stack.pop();
if (value == null) bytes[0] += 4;
else if (typeof value === 'boolean') bytes[0] += 4;
else if (typeof value === 'string') bytes[0] += value.length * 2;
else if (typeof value === 'number') bytes[0] += 8;
else if (typeof value === 'object' && objectList.indexOf(value) === -1) {
objectList.push(value);
if (typeof value.byteLength === 'number') bytes[0] += value.byteLength;
else if (value[Symbol.iterator]) {
// eslint-disable-next-line no-restricted-syntax
for (const v of value) stack.push(v);
} else {
Object.keys(value).forEach(k => {
bytes[0] += k.length * 2; stack.push(value[k]);
});
}
}
}
return bytes[0];
}
It also includes some other minor improvements: counts keys storage and works with ArrayBuffer.
function sizeOf(parent_data, size)
{
for (var prop in parent_data)
{
let value = parent_data[prop];
if (typeof value === 'boolean')
{
size += 4;
}
else if (typeof value === 'string')
{
size += value.length * 2;
}
else if (typeof value === 'number')
{
size += 8;
}
else
{
let oldSize = size;
size += sizeOf(value, oldSize) - oldSize;
}
}
return size;
}
function roughSizeOfObject(object)
{
let size = 0;
for each (let prop in object)
{
size += sizeOf(prop, 0);
} // for..
return size;
}
I use Chrome dev tools' Timeline tab, instantiate increasingly large amounts of objects, and get good estimates like that. You can use html like this one below, as boilerplate, and modify it to better simulate the characteristics of your objects (number and types of properties, etc...). You may want to click the trash bit icon at the bottom of that dev tools tab, before and after a run.
<html>
<script>
var size = 1000*100
window.onload = function() {
document.getElementById("quantifier").value = size
}
function scaffold()
{
console.log("processing Scaffold...");
a = new Array
}
function start()
{
size = document.getElementById("quantifier").value
console.log("Starting... quantifier is " + size);
console.log("starting test")
for (i=0; i<size; i++){
a[i]={"some" : "thing"}
}
console.log("done...")
}
function tearDown()
{
console.log("processing teardown");
a.length=0
}
</script>
<body>
<span style="color:green;">Quantifier:</span>
<input id="quantifier" style="color:green;" type="text"></input>
<button onclick="scaffold()">Scaffold</button>
<button onclick="start()">Start</button>
<button onclick="tearDown()">Clean</button>
<br/>
</body>
</html>
Instantiating 2 million objects of just one property each (as in this code above) leads to a rough calculation of 50 bytes per object, on my Chromium, right now. Changing the code to create a random string per object adds some 30 bytes per object, etc.
Hope this helps.
If you need to programatically check for aprox. size of objects you can also check this library http://code.stephenmorley.org/javascript/finding-the-memory-usage-of-objects/ that I have been able to use for objects size.
Otherwise I suggest to use the Chrome/Firefox Heap Profiler.
I had problems with the above answer with an ArrayBuffer.
After checking the documentation, I found that ArrayBuffer has a byteLength property which tells me exactly what I need, hence:
function sizeOf(data)
{
if (typeof(data) === 'object')
{
if (data instanceof ArrayBuffer)
{
return data.byteLength;
}
// other objects goes here
}
// non-object cases goes here
}
console.log(sizeOf(new ArrayBuffer(15))); // 15
Reference:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer/byteLength
Building upon the already compact solution from #Dan, here's a self-contained function version of it. Variable names are reduced to single letters for those who just want it to be as compact as possible at the expense of context.
const ns = {};
ns.sizeof = function(v) {
let f = ns.sizeof, //this needs to match the name of the function itself, since arguments.callee.name is defunct
o = {
"undefined": () => 0,
"boolean": () => 4,
"number": () => 8,
"string": i => 2 * i.length,
"object": i => !i ? 0 : Object
.keys(i)
.reduce((t, k) => f(k) + f(i[k]) + t, 0)
};
return o[typeof v](v);
};
ns.undef;
ns.bool = true;
ns.num = 1;
ns.string = "Hello";
ns.obj = {
first_name: 'John',
last_name: 'Doe',
born: new Date(1980, 1, 1),
favorite_foods: ['Pizza', 'Salad', 'Indian', 'Sushi'],
can_juggle: true
};
console.log(ns.sizeof(ns.undef));
console.log(ns.sizeof(ns.bool));
console.log(ns.sizeof(ns.num));
console.log(ns.sizeof(ns.string));
console.log(ns.sizeof(ns.obj));
console.log(ns.sizeof(ns.obj.favorite_foods));
I believe you forgot to include 'array'.
typeOf : function(value) {
var s = typeof value;
if (s === 'object')
{
if (value)
{
if (typeof value.length === 'number' && !(value.propertyIsEnumerable('length')) && typeof value.splice === 'function')
{
s = 'array';
}
}
else
{
s = 'null';
}
}
return s;
},
estimateSizeOfObject: function(value, level)
{
if(undefined === level)
level = 0;
var bytes = 0;
if ('boolean' === typeOf(value))
bytes = 4;
else if ('string' === typeOf(value))
bytes = value.length * 2;
else if ('number' === typeOf(value))
bytes = 8;
else if ('object' === typeOf(value) || 'array' === typeOf(value))
{
for(var i in value)
{
bytes += i.length * 2;
bytes+= 8; // an assumed existence overhead
bytes+= estimateSizeOfObject(value[i], 1)
}
}
return bytes;
},
formatByteSize : function(bytes)
{
if (bytes < 1024)
return bytes + " bytes";
else
{
var floatNum = bytes/1024;
return floatNum.toFixed(2) + " kb";
}
},
I know this is absolutely not the right way to do it, yet it've helped me a few times in the past to get the approx object file size:
Write your object/response to the console or a new tab, copy the results to a new notepad file, save it, and check the file size. The notepad file itself is just a few bytes, so you'll get a fairly accurate object file size.
I am trying to do different problems each day in order to become more flexible writing code, yet this one stopped me in my tracks so far.
The following code is supposed to build up a binary tree from a given String in preOrder traversal. I.e., "5 3 1 N N N 7 N N" for the following binary tree. Elements are separated by spaces, N marks empty nodes, which are just null.
5
/ \
3 7
/
1
It should be as simple as walking through the split up string and when something other than "N" is found, a Node is constructed with the value, and the Index increased.
After the index was increased, I recur to put the next array element into the left subtree. If "N" is encountered, nothing needs to be done because a node's constructor already has the left child set as null, so I only increase the index. Theoretically, the right node should be assigned in the previous recursion step... yet somehow that fails?
Is it because of JavaScript's async behaviour? What did I miss?
Thank you in advance for your help!
class Node {
constructor(val) {
this.val = val;
this.left = this.right = null;
}
}
class Index {
constructor() {
this.index = 0;
}
incr() {
this.index++;
}
}
function deserialize(treeString) {
let treeArray = treeString.split(" ");
let index = new Index();
let length = treeArray.length;
function helper(index) {
if (index.index < length) {
let node = null;
if (treeArray[index.index] !== "N") {
node = new Node(parseInt(treeArray[index.index], 10));
index.incr();
node.left = helper(index);
node.right = helper(index);
} else {
index.incr();
}
return node;
};
}
return helper(index);
}
I don't get your error because console.log(JSON.stringify(deserialize('5 3 1 N N N 7 N N'),null,1)) does give me
{
"val": 5,
"right": {
"val": 7,
"right": null,
"left": null
},
"left": {
"val": 3,
"right": null,
"left": {
"val": 1,
"right": null,
"left": null
}
}
}
which seems to be your intended result
we can do a bit "simpler though"
prevent yourself from useless indentation
Especially for stops on recursive condition, it is best practice to write them first
function recurse(){
if (index.index == length) {
//stop code
return
}
//your other conditions...
//your code which will call recurse
}
2.1 your "iterator" here is useless
since you are still dependant to know your structure (treeArray must "implement" operator[]), taking a dumb variable will at least be less code
2.2 if you really want to use an iterator
you see that whether in your if or else path, you incr (which is equivalent to "advance in treeArray"). So just iterate over treeArray. Below we "pop" elements (forwardly")
function helper(arr){
if end
return
let currentNodeVal = arr.shift() //advance in treeArray
if (currentNodeVal !== "N") {
node = new Node(parseInt(currentNodeVal, 10));
node.left = helper(arr);
node.right = helper(arr);
} else {
//nothing to do
}
}
Is it because of JavaScripts async behaviour?
Here you actually don't have any asynchronous code running. If you named
helperinfty = function(){
while(true){}
}
node.left = helperinfty(arr)
node.right = helper(arr);
you could observe that node.right = helper(arr) is never executed. You get the "funky" stuff when you use setTimeout, etc (put it simply when a function needs a callback to sync flow)
(answer is no)
simplified code
prints the same tree as in beginning
class Node {
constructor(val) {
this.val = val;
this.left = this.right = null;
}
}
function deserialize(treeString) {
let arr = treeString.split(" ");
function helper(arr) {
if(arr.length == 0)return null;//note that in previous implem helper "could" return undefined...which is not something desired
let current = arr.shift();
if (current == "N"){
//this is a matter of preference. Arguably one can prefer your style.
//I prefer to emphase that when N is found it is meant to be a null node, and "abort" any recursion
return null
}
let node = new Node(parseInt(current, 10));
node.left = helper(arr);
node.right = helper(arr);
return node;
}
return helper(arr);
}
x = deserialize('5 3 1 N N N 7 N N');
console.log(JSON.stringify(x, null, 4))
I am working on this problem from Coderbyte using JS:
Have the function ArrayAdditionI(arr) take the array of numbers stored in arr and return the string true if any combination of numbers in the array can be added up to equal the largest number in the array, otherwise return the string false. For example: if arr contains [4, 6, 23, 10, 1, 3] the output should return true because 4 + 6 + 10 + 3 = 23. The array will not be empty, will not contain all the same elements, and may contain negative numbers.
The problem seems ripe for a recursive solution, given the branching nature of the need to explore the various combinations of array elements. I would also like to use recursion to get some extra practice.. I'm still very new to coding.
Here is the solution I came up with, and I was very happy about it until I started testing and discovered that it is not at all a solution:
function ArrayAdditionI(arr) {
// sorting the array to easily remove the biggest value
var sArr = arr.sort(function (a, b) {
return a-b;});
// removing the biggest value
var biggest = sArr.pop();
// count will be iterated to stop the recursion after the final element of the array has been processed
var count = 0;
function recursion (start, i) {
if (sArr[i] + start === biggest) {
return true;
}
else if (start + sArr[i] < biggest) {
return recursion(start + sArr[i], i+1);
}
else if (start + sArr[i] > biggest && count < sArr.length) {
count++;
return recursion(0, count);
}
else {
return false;
}
}
return recursion(0,0);
}
This code works only if the array elements which can be summed to fulfill the base case are adjacent to each other; calling ArrayAdditionI([1,2,3,4]), for example, will not work because the two elements which must be summed to reach the target value("1" in position 0, and "3" in position 2) are not adjacent.
My flow will return 1, then 1+2, then 1+2+3, then 2, then 2+3, then 3, and finally return false since the target (4) was not reached.
I can visualize how a proper solution needs to flow through a given array, but I don't know how to make this happen through recursion. For the given array [1,2,3,4], the flow should check results in this pattern: (position0, pos0+pos1, pos0+pos2, pos0+pos1+pos2, pos2, pos2+pos3, pos3). Can anyone give me a nudge? I'm going to think on this more before I sleep in an hour and give it a fresh go in the morning.. maybe my brain just needs a recharge.
Again, I'm really new to this, if I've made some very silly mistakes please let me know, I'll learn from them. Thanks!
Your algorithm has a flaw. Your function looks only one step forward.
You need to add loop inside to look over all rest values.
function ArrayAdditionI(arr) {
// sorting the array to easily remove the biggest value
// slice added to prevent original array modification
var sArr = arr.slice().sort(function (a, b) {
return a - b;
});
// removing the biggest value
var biggest = sArr.pop();
function recursion(start, i) {
var result = false;
// looking over all rest values of array
for (var j = i; j < sArr.length && !result; j++) {
if (sArr[j] + start === biggest) {
result = true;
}
else if (start + sArr[j] < biggest) {
result = recursion(start + sArr[j], j + 1);
}
}
return result;
}
return recursion(0, 0);
}
function ArrayAdditionI (arr) {
var sArr = arr.sort(function (a,b) {
return a-b;
});
var biggest = sArr.pop();
function recursion (start, indx) {
if (start + sArr[indx] === biggest) {
return true;
}
else if (sArr.length < indx) {
return false;
}
else if (start + sArr[indx] < biggest) {
return recursion(start + sArr[indx], indx + 1) || recursion(start, indx+1)
}
else {
return false;
}
}
return recursion(0,0);
}