Java Code sample 1:
ArrayList<ArrayList<Integer>> outerList = new ArrayList<ArrayList<Integer>>();
for(i=0; i<5000; i++){
outerList.add(new ArrayList<Integer>());
for(j=0; j<5000; j++){
outerList.get(i).add(1);
}
}
Java Code sample 2:
ArrayList<ArrayList<Integer>> outerList_n = new ArrayList<ArrayList<Integer>>();
ArrayList<Integer> innerList_n = new ArrayList<Integer>();
for(j=0; j<5000; j++){
innerList_n.add(1);
}
for(i=0; i<5000; i++){
outerList_n.add(innerList_n);
}
Description:
Code sample 1 creates a new arrayList everytime for adding to the outerlist, although every entry for the innerList in always 1.
Code sample 2 creates one array with the all entries as 1 and then adds it to the outerList in the for loop.
Questions:
1) Do they both have different memory footprints or same?
I used jdk.nashorn.internal.ir.debug.ObjectSizeCalculator to calculate it and the following are the results:
Size of outerList: 514907072
Size of outerList_n: 130048
2) I do not understand why the above difference in memory. Isn't the data structure same in both cases?
3) Is this the same case in javascript? When I tried the respective codes for javascript for the above 2 scenarios, I got the same memory footprint in both cases.
Javascript Code:
function sizeof(object){
// initialise the list of objects and size
var objects = [object];
var size = 0;
// loop over the objects
for (var index = 0; index < objects.length; index ++){
// determine the type of the object
switch (typeof objects[index]){
// the object is a boolean
case 'boolean': size += 4; break;
// the object is a number
case 'number': size += 8; break;
// the object is a string
case 'string': size += 2 * objects[index].length; break;
// the object is a generic object
case 'object':
// if the object is not an array, add the sizes of the keys
if (Object.prototype.toString.call(objects[index]) != '[object Array]'){
for (var key in objects[index]) size += 2 * key.length;
}
// loop over the keys
for (var key in objects[index]){
// determine whether the value has already been processed
var processed = false;
for (var search = 0; search < objects.length; search ++){
if (objects[search] === objects[index][key]){
processed = true;
break;
}
}
// queue the value to be processed if appropriate
if (!processed) objects.push(objects[index][key]);
}
}
}
// return the calculated size
return size;
}
// TWO SEPARATE FOR LOOPS
var start = new Date().getTime();
var i,j ;
var inner_arr1 = [];
var outer_arr1 = [];
for (i = 0; i < 100; i++) {
inner_arr1.push("abcdefghijklmnopqrstuvwxyz");
}
for (j = 0; j < 100; j++) {
outer_arr1.push(inner_arr1);
}
var end = new Date().getTime();
print("size of outer_arr1: "+sizeof(outer_arr1));
print("time of outer_arr1 (in ms): "+(end-start))
// NESTED FOR LOOPS
var start = new Date().getTime();
var outer_arr2 = [];
for (j = 0; j < 100; j++) {
var inner_arr2 = [];
for (i = 0; i < 100; i++) {
inner_arr2.push("abcdefghijklmnopqrstuvwxyz");
}
outer_arr2.push(inner_arr1);
}
var end = new Date().getTime();
print("size of outer_arr2: "+sizeof(outer_arr2));
print("time of outer_arr2 (in ms): "+(end-start))
/*
COMMAND:
jjs findingSize.js
OUTPUT:
size of outer_arr1: 52
time of outer_arr1 (in ms): 45
size of outer_arr2: 52
time of outer_arr2 (in ms): 58
*/
Do they both have different memory footprints or same?
Different. In the first case you are creating 5001 instances of ArrayList. In the second you are creating only two instance of ArrayList
Isn't the data structure same in both cases?
The structure of data is the same in both cases - you have array of arrays. The only difference is that in the second case all your innner arrays are same - they share the common memory and when you change value in some row, all rows will be changed
Code sample 1 : it will create 5000 different Lists filled with 5000 times the value 1, all saved in outerList : 5000+1 = 5001 different List
Code sample 2 : outerList contains 5000 times the same list (filled with 5000 times values 1) : 1+1 = 2 different Lists
Seems to me the evaluation is correct. Your first code sample has an inner loop. This is exponentially more than the second sample.
To put it plainly, the 2nd sample will iterate the first loop 5000 times, then the second loop 5000 times.
The first example will iterate the innerloop 5000 times, for each loop of the outer loop (another 5000 times) so you get 5000*5000 iterations ofouterList.get(i).add(1).
I hope this answers your question.
Related
So I was asked to create an algorithm that when given a basic input of an array of counts and sites, it will output the accumulated visits to each TLD and Subdomain represented in a JSON object that will yield data like:
1120 com
800 google.com
310 reddit.com
60 mail.yahoo.com
10 mobile.sports.yahoo.com
50 sports.yahoo.com
10 stackoverflow.com
3 org
3 wikipedia.org
2 en.wikipedia.org
2 es.wikipedia.org
1 mobile.sports
1 sports
The input is something like:
// visits = [ "800,google.com",
// "60,mail.yahoo.com",
// "10,mobile.sports.yahoo.com",
// "40,sports.yahoo.com",
// "310,reddit.com",
// "10,stackoverflow.com",
// "2,en.wikipedia.org",
// "1,es.wikipedia.org",
// "1,mobile.sports" ]
My code looks like this so far and I know its wrong, but my brain is melted at the moment and I am not sure how to proceed. I am not necessarily looking for you to write the algorithm for me, but I do want to understand logically how I could break this down.
function getDomainHits(arr){
var splitCount = [];
var splitDomains = [];
var domainCountDict = {"Domains" : [],"Count" : 0};
for (var i = 0; i < arr.length; i++){
splitCount = arr[i].split(",");
splitDomains = splitCount[1].split(".");
for (var j = 0; j < splitDomains.length; j++){
if (!domainCountDict.Domain.includes(splitDomains[j])){
domainCountDict.Domain.push(splitDomains[j]);
}
}
}
console.log(domainCountDict);
}
As you can see I stopped here because I couldn't think of the best way to split these into different key, value pairs - one being domains and the other being the counts. Also my algorithm doesn't exactly follow the requirements.
So I figured out the algorithm. Define a variable - initialize it as an Array, and a dictionary to store the processed array data.
var splitCount = [];
var domainCountDict = {};
Then you need to take the Array of strings (arr - the function parameter) and iterate through it. On each iteration you need to split the string element into another Array to further process it.
for (var i = 0; i < arr.length; i++){
splitCount = arr[i].split(",");
...
}
So for the example input data of
// visits = [ "800,google.com",
// "60,mail.yahoo.com",
// "10,mobile.sports.yahoo.com",
// "40,sports.yahoo.com",
// "310,reddit.com",
// "10,stackoverflow.com",
// "2,en.wikipedia.org",
// "1,es.wikipedia.org",
// "1,mobile.sports" ]
Iteration 0 would be split into an Array of ["800","google.com"] and assigned to Var splitCount. You would then need to access splitCount and because of the input formatting you don't need to create a for loop. I created a variable to store the current count of the site - which will always be element 0 because of the format of the input data.
I didn't bother with input sanitation here because I didn't have time to create a map function that will turn the number elements into - well... numbers. I relied on the assumption that the input data will always have a number in the 0th index - which is terrible. Don't do this.
var curCnt = 0;
if (splitCount[0]){
curCnt = splitCount[0];
}
This next chunk of logic hurt my brain a little bit because I needed to find a way to store each domain component and its count in the dict and determine if the other domains contained components that already existed and if so increment those. Lets make some more Arrays!
var domain = [];
var currentDom = [];
if (splitCount[1] != undefined && splitCount[1]){
domain = splitCount[1].split(".");
for (var j = domain.length - 1; j >= 0; j--){
...
}
}
Above you will see that created an Array to hold the domain components called domain and another called currentDom to hold the components that are being worked and have already been worked, because we want to make sure that we count com and google.com. Lets look inside of the for loop.
for (var j = domain.length - 1; j >= 0; j--){
currentDom.unshift(domain.pop());
/*console.log("current iter: " + k + "\n"
+ "currentDom: " + currentDom.join(".") + "\n"
+ "current count: " + curCnt + "\n");*/
if (currentDom.join(".") in domainCountDict){
/*console.log("currentDom2: " + currentDom.join("."));
console.log("increment existing");*/
domainCountDict[currentDom.join(".")] += parseInt(curCnt);
}
if (!(currentDom.join(".") in domainCountDict)){
/*console.log("currentDom3: " + currentDom.join("."));
console.log("increment new");*/
domainCountDict[currentDom.join(".")] = parseInt(curCnt);
//console.log(domainCountDict);
}
}
Above you will see that I am iterating backwards in this loop to work the TLD first and then the domains/subdomains. I chose to pop the last element off the end of the current array and unshift it to the beginning of the new Array, currentDom. This will effectively let me work on a portion of the entire FQDN to determine if it has been included in the dictionary.
I have a few if statements to determine if the currentDom is included in the array. I had to use Array.join() to accurately check if the string of the current domain components have been included in the dictionary. If not then the string of currentDom would be added as a key and the curCnt would be the value assigned. If so, then the value would be incremented. Because of my lazy input sanitation in the curCnt assignment I had to parse these as Int because JS dynamic types. I am sure there is a better way, but my brain hurts now.
Finally make sure that you return the created dictionary on the outside of all of these for loops.
The full algorithm is below
// Sample output (in any order/format):
// getTotalsByDomain(counts)
// 1320 com
// 900 google.com
// 410 yahoo.com
// 60 mail.yahoo.com
// 10 mobile.sports.yahoo.com
// 50 sports.yahoo.com
// 10 stackoverflow.com
// 3 org
// 3 wikipedia.org
// 2 en.wikipedia.org
// 1 es.wikipedia.org
// 1 mobile.sports
// 1 sports
let counts = [ "900,google.com",
"60,mail.yahoo.com",
"10,mobile.sports.yahoo.com",
"40,sports.yahoo.com",
"300,yahoo.com",
"10,stackoverflow.com",
"2,en.wikipedia.org",
"1,es.wikipedia.org",
"1,mobile.sports" ];
console.log(getDomainHits(counts));
function getDomainHits(arr){
var splitCount = [];
var domainCountDict = {};
for (var i = 0; i < arr.length; i++){
splitCount = arr[i].split(",");
var curCnt = 0;
if (splitCount[0]){
curCnt = splitCount[0];
}
var domain = [];
var currentDom = [];
if (splitCount[1] != undefined && splitCount[1]){
domain = splitCount[1].split(".");
for (var j = domain.length - 1; j >= 0; j--){
currentDom.unshift(domain.pop());
/*console.log("current iter: " + k + "\n"
+ "currentDom: " + currentDom.join(".") + "\n"
+ "current count: " + curCnt + "\n");*/
if (currentDom.join(".") in domainCountDict){
/*console.log("currentDom2: " + currentDom.join("."));
console.log("increment existing");*/
domainCountDict[currentDom.join(".")] += parseInt(curCnt);
}
if (!(currentDom.join(".") in domainCountDict)){
/*console.log("currentDom3: " + currentDom.join("."));
console.log("increment new");*/
domainCountDict[currentDom.join(".")] = parseInt(curCnt);
//console.log(domainCountDict);
}
}
}
}
return domainCountDict;
}
I am just learning how to program in javascript and I made my first program that "does something". I didn't look for help for any part of the algorithm, just in some parts to find the name of a function I wanted to use. This algorithm seems to work, but it doesnt seem to finish when you have a big list of number, like 10 or more. What yo do you think of it? Is wholly ineficient?
var totNum = Number(prompt("How many numbers you want to compare"));
var unordNum = new Array(totNum);
var ordNum = new Array();
for( var i=1 ; i<= totNum; i++){
unordNum[i] = Number(prompt("Write a new number","0"));
}
while(ordNum.length < totNum){ // I will repeat this process until I order all numbers
for(var i=1; i <=totNum; i++){ //choose a number, lets call it X
if(!(ordNum.indexOf(unordNum[i]) >=0)){ //if it is already ordered, skip it
var z = 0;
for(var j=1; j<=totNum; j++){ //I will compare X against all the others numbers, except
if(!(ordNum.indexOf(unordNum[j]) >= 0)){ //the ones that are already ordered
if( unordNum[i] >= unordNum[j]){ //if X is bigger than a number,
z++; // add 1 to z
}
if(z==totNum-ordNum.length){ // this means X is bigger or equal than all the other numbers
ordNum.push(unordNum[i]); //so write X in the first empty space of the ordered list
}
}
}
}
}
}
document.write(ordNum + "<br>");
You make use of ordNum.indexOf(unordNum[j]) to find if a number is already sorted. This would lead to an infinite loop in case of duplicates. Secondly, you are not really sorting, you would push a number for the first comparison success.
Below is a somewhat similar logic for your sorting.
var totNum = Number(prompt("How many numbers you want to compare"));
var unordNum = new Array(totNum);
var ordNum = new Array();
for( var i=0 ; i< totNum; i++){
unordNum[i] = Number(prompt("Write a new number","0"));
}
for(var i=0; i <totNum; i++){
if(unordNum[i] == undefined) continue; //jump to the next unsorted number
var smallest = unordNum[i]; //initialize smallest to be the first unsorted number
var index = i; //initialize marker index to be set as undefined at last for the number being moved to the sorted array
for(var j=0; j<totNum; j++){ //Comparison loop to find the smallest
if(unordNum[j] != undefined){
smallest = unordNum[j]<smallest ? unordNum[j] : smallest; //Swap if j th number is smaller
index = smallest == unordNum[j] ? j : index; // update index if swapping done
}
}
unordNum[index] = undefined;//mark the number moved
ordNum.push(smallest); // add smallest number to sorted array
i=0; //set outer loop to start from 0 again
}
document.write(ordNum + "<br>");
This would sort by copying the smallest number in the remaining array into a new array. Instead of using ordNum.indexOf(unordNum[j]) as you did, I am marking the sorted element as undefined. Duplicates cannot be sorted in your case. This would leave the new sorted array smaller than the input array and hence an infinite loop. Another thing, why do you use 1 as the starting index? The default index starts from 0 in Javascript as well.
There are far better sorting algorithms but perhaps that is not what you are looking for.
Once you have numbers in array, you can use array.sort()
This question already has answers here:
Split array into chunks of N length [duplicate]
(2 answers)
Closed 5 years ago.
I am trying to build an airport style terminal arrival/departure table view. Trying to make the rows viewable dynamic depending on viewable window.
I have an array that could have any number of rows. Each row is an array itself. I am trying to break up the rows in the array into chunks depending on how much table rows the view can support.
So my question is I'm not sure how to break it up into chunks properly depending on dynamic sizes I want the chunks to be in. I've tried slice and splice but it only adds to the first element in the shortArrays then the rest of the elements are all empty.
INCOMING DATA:
array([array1], [array2], [array3], [array4], [array5], [array6], [array7], [array8], [array9], [array10], [array11], [array12], [array13]), [array14]), [array15]))
OUTGOING DATA:
array([[array1], [array2], [array3], [array4], [array5], [array6], [array7], [array8], [array9], [array10]], [[array11], [array12], [array13], [array14], [array15]]) // 2 rows, row1: 10 arrays, row2: 5 arrays
var jsonData = JSON.parse(data); // data is value returned from ajax
var maxRowsPerTableView = 10; // Hardcoded as an example
var totalTablesToMake = 2; // Hardcoded as an example
var longArray = jsonData;
var shortArrays = [];
var tempCount, doorCount = 0; // Keeps track of which index
for(a = 0; a < totalTablesToMake; a++)
{
temp = [];
for(b = 0; b < maxRowsPerTableView; b++)
{
temp.push(longArray[b + doorCount]);
tempCount = b;
}
doorCount += tempCount;
shortArrays.push(temp);
}
RESULT:
shortArrays([10 elements],[10 elements]) // This isn't actual output, just a visual description so you can see what results I get.
This current code will output: shortArrays with 2 rows, each rows have 10 elements. So let's say there is only 15 elements in the jsonData. The second row in shortArrays will still have 10 elements, but the last 5 will be undefined.
longArray[b + doorCount]
will return undefined if youre out of the arrays bounds. So you either fill in sth else ( an Array for Example)
longArray[b + doorCount]||[];
Or you stop the loop then:
mainloop:for(a = 0; a < totalTablesToMake; a++)
{
temp = [];
for(b = 0; b < maxRowsPerTableView; b++)
{
if(b+a*maxRowsPerTableView>=longArray.length) break mainloop;
temp.push(longArray[b + doorCount]);
tempCount = b;
}
doorCount += tempCount;
shortArrays.push(temp);
}
I've written a function that takes plevel (integer) and slevel (array of strings of numbers) and finds the smallest difference between plevel and a value in slevel. However, when I run the script, it is unresponsive and the debugger says that diff is undefined.
var findDiff = function findDiff(plevel, slevel) {
var diff = new Array();
for (i=0; i<=slevel.length; i++) {
sleveli = parseInt(slevel[i]);
diff.push(Math.abs(plevel-sleveli));
}
if (diff.length > 1){
diff.sort(function(a, b){return a-b});
return diff[0]
}
else{
return diff[0];
}
}
The function is invoked here:
var matches = new Array();
var newFetch = Data.find().fetch();
for(i = 0; i <= newFetch.length; i++ ){
pointsMatch = 0
var difference = findDiff(newFetch[i].level, spec.level);
pointsMatch -= (difference*3);
matches.push([newFetch[i], pointsMatch])
}
console.log(matches)
Data is a mongoDB collection. spec.level is an array of strings of numbers stored as a property in an object.
I would like to point out name space pollution, which may cause serious troubles. In my understanding, you have two cases of namespace pollution, one of it creates an endless loop.
You have actually an inner an outer loop, separated by a function. Your outer for loop:
for(i = 0; i <= newFetch.length; i++ ){
pointsMatch = 0
...
And then your inner for loop:
for (i=0; i<=slevel.length; i++) {
sleveli = parseInt(slevel[i]);
...
Because of the missing var before i, both for loop definitions are actually like this:
for (window.i=0; ...
So the inner loop overwrites the variable i the outer loop depends on to terminate. i is "polluting" namespace.
The second case is harmless:
sleveli = parseInt(slevel[i]);
Because of the missing var, this results in fact in
window.sleveli = parseInt(slevel[i]);
Better would be
var sleveli = parseInt(slevel[i]);
But this is a time bomb.
I suggest you add var to the definitions of i in the for loop.
I think the people in the comments are right; we need to see some more of your input to debug this properly. But you can simplify your code a lot by tracking the mins as you go:
var findDiff = function findDiff(plevel, slevel) {
var min = Number.MAX_SAFE_INTEGER;
for (i=0; i<slevel.length; i++) {
sleveli = parseInt(slevel[i]);
var diff = Math.abs(plevel-sleveli);
min = Math.min(min, diff)
}
return min;
}
var a = ["1", "2", "10", "17"]
var p = 6
// We're expecting 4 as the min diff
console.log(findDiff(p, a))
// ...prints out 4 :-)
http://repl.it/ceX
As Omri points out, use < not <= in your for loop.
Note - Number is not always available -- see here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER
You could alternatively set the initial min to something suitably large for your likely data, like 2^10
Given an array of values:
var values = new Array();
array.push(2);
array.push(3);
array.push(4);
I'd like to create an iterative function which can store every possible combination of values, for any length of array.
For example, in this case the possible values would be (1,1,1)(1,1,2)(1,1,3)(1,1,4)(1,2,1)(1,2,2)(1,2,3)(1,2,4)(2,1,1)(2,1,2)(2,1,3)(2,1,4)(2,2,1)(2,2,2)(2,2,3)(2,2,4)
I know that to do this I need to use an recursive function, which will go a level deeper and call the function again if the maximum depth has not been reached...
I know where to start is (probably, I think)
function iterativeLoop(level, depth) {
for(var i = 0; i < values.length; i++) {
if(level < depth) {
iterativeloop(level+1, depth);
}
else if (level=depth) {
}
}
}
I'm not sure how I can access the 'upper' levels once the function is called deeper though... i.e. I'm not sure how to access (1,2,4) and not just (?,?,4)
I hope that makes sense?
(Sorry I know my title isn't very good, I couldn't think how to concisely explain it)
I'm not sure how I can access the 'upper' levels once the function is called deeper though... i.e. I'm not sure how to access (1,2,4) and not just (?,?,4)
You will need to pass them on, e.g. in an array.
for(var i = 0; i < values.length; i++)
This should not be the outer iteration to perform, unless you want to construct a two-dimensional array of results in a simple nested loop (see below). Instead, you want value.length to be the depth you are recursing to. On every recursion level, you will iterate from 1 to values[level] then. And instead of passing a level, we will pass an array of the current state (the question marks from above) whose length is the level.
var values = [2,3,4];
function recurse(state) {
var level = state.length;
var depth = values.length;
if (level == depth) {
console.log.apply(console, state); // or whatever you want to do
} else {
for (var i=1; i<=values[level]; i++) {
state.push(i); // save current question mark
// notice state.length = level + 1 now
recurse(state); // enter next level
state.pop(); // delete it after we're so state doesn't grow infinitely :-)
}
}
}
recurse([]);
If you want to use your iteration over the values, you can do so by adding more and more states to a result array (growing by one value each level), which in the end will contain all possible combinations:
var values = [2,3,4];
var result = [[]]; // one empty state at level 0
for (var i=0; i<values.length; i++) {
var reslen = result.length,
val = values[i];
var mult = []; // will become the new result with a length of (reslen * val)
for (var j=0; j<reslen; j++) {
for (var k=1; k<=val; k++) {
var state = result[j].slice(); // make a copy
state.push(k);
mult.push(state);
}
}
result = mult;
}
// logging the `result` on each level will show us
// 0 - [[]]
// 1 - [[1],[2]]
// 2 - [[1,1],[1,2],[1,3],[2,1],[2,2],[2,3]]
// 3 - [[1,1,1],[1,1,2],[1,1,3],[1,1,4],[1,2,1],[1,2,2],[1,2,3],[1,2,4],[1,3,1],[1,3,2],[1,3,3],[1,3,4],[2,1,1],[2,1,2],[2,1,3],[2,1,4],[2,2,1],[2,2,2],[2,2,3],[2,2,4],[2,3,1],[2,3,2],[2,3,3],[2,3,4]]
You can see how this is similar to #Jason's approach.
You don't need recursion since the length of the arbitrary data set is defined at the beginning at runtime:
var numbers = [2,3,4];
var result_array = [];
var num_product = 1;
var i=0, j=0, k=0; // iterators
for (i=0; i<numbers.length; i++) {
num_product *= numbers[i];
}
for (i=0; i<num_product; i++) {
result_array.push([]);
}
for (i=0; i<result_array.length; i++) {
product = 1;
for (j=0; j<numbers.length; j++) {
k = (Math.floor(i/product)%numbers[j]) + 1;
product *= numbers[j];
result_array[i][j] = k;
}
}
tested and functional for any number of array elements.
A side-by-side benchmark shows this code to be significantly faster than the recursive code - if you are able to avoid recursion (e.g. you know enough information up front to be able to define the whole problem) then it's better to do so, and the problem as currently defined allows you to do that. If you're just trying to learn about recursion, then this isn't very helpful to you :)