add element to ordered array in CoffeeScript - javascript

I have a sorted array, which I add elements to as the server gives them to me. The trouble I'm having is determining where to place my new element and then placing it in the same loop
in javascript this would look like this
for(var i = 0; i < array.length; ++i){
if( element_to_add < array[i]){
array.splice(i,0,element_to_add);
break;
}
}
The problem is that in coffee script I dont have access to the counter, so I cant tell it to splice my array at the desired index.
How can I add an element to a sorted array in CoffeeScript?

The default for loop returns the index as well:
a = [1, 2, 3]
item = 2
for elem, index in a
if elem >= item
a.splice index, 0, item
break
You may want to do a binary search instead.

If you are using Underscore.js (very recommended for these kind of array manipulations), _.sortedIndex, which returns the index at which a value should be inserted into an array to keep it ordered, can come very handy:
sortedInsert = (arr, val) ->
arr.splice (_.sortedIndex arr, val), 0, val
arr
If you're not using Underscore, making your own sortedIndex is not that hard either; is's basically a binary search (if you want to keep its complexity as O(log n)):
sortedIndex = (arr, val) ->
low = 0
high = arr.length
while low < high
mid = Math.floor (low + high) / 2
if arr[mid] < val then low = mid + 1 else high = mid
low

If I understood you correctly, why not save the position, like so,
var pos=-1;
for(var i = 0; i < array.length; ++i){
if( element_to_add < array[i]){
pos=i; break;
}
}
if(pos<0)
array.push(element_to_add);
else array.splice(pos,0,element_to_add);

Related

Sort an array element closest to known element based on it's index

Let's assume an array
Example 1 :
let arr = [101,102,104,103,105]
known_element = 104;
//Output [104,102,103,101,105]
Example 2 :
let arr = [4,6,3,5,1,9,2,7,8]
known_element = 9;
//Output [9,1,2,5,7,3,8,6,4]
Sort the above array in such a way,
known_element should be always at 0th element
second,third.. element should be closest to known_element by it's index not by value
Note: sorting should be done based on index closest to known_element.
It makes sense to find location of known number first
var pos = arr.indexOf(known_element);
Then we are going to loop up and down, getting numbers from closest to farthest. Let's see to which side is longer length.
var length = Math.max(pos, arr.length - pos + 1)
Ok, our result array is ready (to be filled), lets loop
var result = [known_element];
for (var i = 1; i < length; i++) {
if (pos- i >= 0) {
result.push(arr[pos - i])
}
if (pos + i < arr.length) {
result.push(arr[pos + i]);
}
}
I think that's it!
Test and let me know which edge case I forgot.

Creating new array from unique elements found in array

I was given an assignment:
Finding unique elements in an array and creating a new array from these unique elements.
The professor gave us the pseudocode to code this assignment - it should be straightforward but my code is not working.
Here is my attempt:
// search for unique birthdays in the array
function find(birthdays) {
var uniqueBirthdays = [];
for (var i = 1; i <= birthdays.length; i = i + 2) {
var count = 0;
for (var j = 1; j <= birthdays.length; j = j + 2) {
if (birthdays[i] == birthdays[j]) {
count++;
}
}
if (count == 1) {
var n = uniqueBirthdays.length;
uniqueBirthdays[n] = birthdays[i - 1];
}
}
return uniqueBirthdays;
}
I have tried checking for indentation errors as well as a number of other things but can not figure out why as the array is traversed it is giving each element a count of only 1 (meaning there are no matching elements) - it does not seem to be traversing the array more than once so no elements have a count greater than 1 - even though I am using nested for loops.
I have increased the intervals by 2 because I need to compare every other element - there is a number assigned to each birthday so the array may look like:
['0001'][12/15]['0002'[03/12]...
I am brand new so I may be overlooking simple but ive tried so many things and i can not understand why this code isnt working - it is returning back all of the elements that are assigned to the birthdays instead of just the unique ones.
Any help that will point me in the right direction is very much appreciated.
You were very close, and there were just a couple mistakes. The only things that did not work were the way you wrote your for loops:
for (var i = 1; i <= birthdays.length; i = i + 2) {
Array indexes start at 0, so if you want to process the first element, use var i = 0;
Since these indexes start at 0, for an Array of 3 elements, the last index is 2. So you only want to run your loop while i is less than the array length: i < birthdays.length
You were skipping elements by doing i = i + 2. There seems to be no reason for it?
Something else worth mentionning: in JS, indentation does not matter - well, it does, but only to avoid making your eyes bleed. In fact, most websites use minified versions of their code, which fits on a single (often very long and ugly) line (example).
Here is your code, with only two lines fixed:
function find(birthdays) {
var uniqueBirthdays = [];
for (var i = 0; i < birthdays.length; i = i + 1) { // <-----
var count = 0;
for (var j = 0; j < birthdays.length; j = j + 1) { // <-----
if (birthdays[i] == birthdays[j]) {
count++;
}
}
if (count == 1) {
var n = uniqueBirthdays.length;
uniqueBirthdays[n] = birthdays[i];
}
}
return uniqueBirthdays;
}
// I used letters instead of birthdays for easier demo checking
var birthdays = ['a', 'b', 'a', 'c'];
console.log( find(birthdays) ); // ["b", "c"]
JS have direct methods tor that use Array.indexOf(), Array.lastIndexOf() and Array.filter()
uniques elements have same first position and last position
sample code:
const initailArray = [...'ldfkjlqklnmbnmykdshgmkudqjshmjfhmsdjhmjh']
const uniqueLetters = initailArray.filter((c,i,a)=>a.indexOf(c)===a.lastIndexOf(c)).sort()
console.log(JSON.stringify(uniqueLetters))

Is this the right way to iterate through an array?

Here is the code in question:
var L1 = [];
var Q1 = [];
function populateListOne() {
var limit = prompt("please enter a number you would like to fill L1 to.");
for (i = 2; i <= limit; i++) {
L1[i] = i;
}
for (n = 2; n <= L1.length; n++) {
var count = 2;
if (n == count) {
var index = L1.indexOf(n);
L1.splice(index, 1);
Q1[n] = n;
count = count + 1;
}
for (j = 0; j <= L1.length; j++) {
if (L1[j] % 2 == 0) {
var secondIndex = L1.indexOf(j);
L1.splice(secondIndex, 1);
}
}
}
document.getElementById("demo").innerHTML = "iteration " + "1" + ": " + L1 + " Q1 = " + Q1;
}
I’m currently working on a homework assignment where I have to setup a queue. All is explained in my JSFiddle.
Problem description
Essentially, the part I’m stuck on is iterating through each instance of the array and then taking the value out if the modulus is identical to 0. However, as you can see when I run the program, it doesn’t work out that way. I know the problem is in the second for loop I just don’t see what I’m doing wrong.
The way I read it is, if j is less than the length of the array, increment. Then, if the value of the index of L1[j] modulus 2 is identical to 0, set the value of secondIndex to whatever the index of j is. Then splice it out. So, theoretically, only numbers divisible by two should be removed.
Input
A single number limit, which will be used to fill array L1.
L1 will be initialized with values 2, 3, ... limit.
Process
Get the starting element of array L1 and place it in array Q1.
Using that element, remove all values in array L1 that are divisible by that number.
Repeat until array L1 is empty.
You're going to have issues with looping over an array if you're changing the array within the loop. To help with this, I tend to iterate from back to front (also note: iterate from array.length - 1 as the length element does not exist, arrays are key'd from 0):
for(j = L1.length - 1; j >=0 ; j--)
For your first loop, you miss the elements L1[0] and L1[1], so I would change the first loop to:
L1 = [];
for(i = 2; i <= limit; i++)
{
L1.push(i);
}
In this section:
for(j = 0; j <= L1.length; j++){
if(L1[j] % 2 == 0)
{
var secondIndex = L1.indexOf(j);
L1.splice(secondIndex, 1);
}
}
you should splice with j instead of secondIndex.
Change L1.splice(secondIndex, 1); to L1.splice(j, 1);
Array indices and putting entries
You initial code used an array that was initialized to start at index 2. To avoid confusion, of what index to start at, start with index 0 and iterate until array.length instead of a predefined value limit to ensure that you go through each element.
The following still works but will be more of a headache because you need remember where to start and when you will end.
for (i = 2; i <= limit; i++) {
L1[i] = i; // 'i' will begin at two!
}
Here's a better way:
for (i = 2; i <= limit; i++) {
// 'i' starts at 2 and since L1 is an empty array,
// pushing elements into it will start index at 0!
L1.push(i);
}
Use pop and slice when getting values
When you need to take a peek at what value is at the start of your array, you can do so by using L1[0] if you followed my advice above regarding array keys.
However, when you are sure about needing to remove the starting element of the array, use Array.slice(idx, amt). idx specifies which index to start at, and amt specifies how many elements to remove beginning at that index (inclusive).
// Go to 1st element in L1. Remove (1 element at index 0) from L1.
var current = L1.splice(0, 1);
Use the appropriate loops
To make your life easier, use the appropriate loops when necessary. For loops are used when you know exactly how many times you will iterate. Use while loops when you are expecting an event.
In your case, 'repeat until L1 is empty' directly translates to:
do {
// divisibility checking
} while (L1.length > 0);
JSFiddle
Here's a complete JS fiddle with in-line comments that does exactly what you said.

how to optimize code in javascript

I think the code(below) is optimized (just use less variables than my initial version of the same logic).
How do I really know if its properly optimized ?
What factors should I consider during optimization ?
Here is the code (
also on jsfiddle )
function process(arr){
var processed = [];
for(var i=0,len=arr.length;i<len;i++){
if(processed.indexOf(arr[i]) < 0){
var nodes = findIndexes(arr,arr[i]);
if(nodes.length > 1){
for(var j=0,jlen=nodes.length;j<jlen;j++){
arr[nodes[j]] = arr[nodes[j]] + '(' + ( j + 1 ) + ')';
}
}
processed.push(arr[i]);
}
}
return arr;
}
function findIndexes(arr,val){
var node = [];
for(var i=0,len=arr.length;i<len;i++){
if(arr[i] === val){
node.push(i);
}
}
return node;
}
// input
var arr = ['aa','bb','bb','aa','cc','dd','cc','ff']
console.log(process(arr));
//output: ["aa(1)", "bb(1)", "bb(2)", "aa(2)", "cc(1)", "dd", "cc(2)", "ff"]
Here is the explanation of the code. 'process' function looks for the same values inside array and for every same values it changes the value by post pending a number to that values, "number" indicates the count of the value as it found in array.
for example
arr = ["x","x","y","z"] will return ["x(1)","x(2)","y","z"]
"y" and "z" are unchanged because they appeared only once.
To optimize I have used an array named as processed that is used to hold values that are just processed inside main for loop, so in next iterations it can be determined that the new iteration value is already processed or not by checking through the array.indexOf method, if the value is already processed then it can safely skip the underlying logic (if/for statements).
Now I have no idea how to further optimize it other than changing the whole process logic.
Optimizations in a broad sense will involve simplifying code, precomputing results which are repeatedly reused, and organizing code so more results can be reused.
Your fiddle code produced following result on analysis.
Logical LOC: 26
Mean parameter count: 3
Cyclomatic complexity: 7
Cyclomatic complexity density: 27%
Maintainability index: 104
Lines of Code (LOC)– Indicates the approximate number of lines in the code. The count is based on the IL code and is therefore not the exact number of lines in the source code file. A very high count might indicate that a type or method is trying to do too much work and should be split up. It might also indicate that the type or method might be hard to maintain.
Maintainability Index – Calculates an index value between 0 and 100 that represents the relative ease of maintaining the code. A high value means better maintainability. Color coded ratings can be used to quickly identify trouble spots in your code. A green rating is between 20 and 100 and indicates that the code has good maintainability. A yellow rating is between 10 and 19 and indicates that the code is moderately maintainable. A red rating is a rating between 0 and 9 and indicates low maintainability.
Cyclomatic Complexity – Measures the structural complexity of the code. It is created by calculating the number of different code paths in the flow of the program. A program that has complex control flow will require more tests to achieve good code coverage and will be less maintainable.
Check code complexities using online tool for your javascript code.
Reference : Link1,Link 2
Javascript optimiser page
Reference(Provides you with different techniques that you should keep in mind while optimising)
You can do it in a single loop:
function process2(arr) {
var out = arr.slice(0),
seen = {},
len = arr.length,
i, key, item, count;
for (i = 0; i < len; ++i) {
key = out[i];
item = seen[key];
if (!item) {
// firstIndex, count
seen[key] = item = [i, 0];
}
count = ++item[1];
if (count > 1) {
if (count === 2) {
out[item[0]] = key + '(1)';
}
out[i] = key + '(' + count + ')';
}
}
return out;
}
// input
var arr = ['aa', 'bb', 'bb', 'aa', 'cc', 'dd', 'cc', 'ff']
console.time('p2');
console.log(process2(arr));
console.timeEnd('p2');
From benchmarking, process2 is approximately 2x faster than process1. That's just a really naive first pass at the problem.
And yet another way to optimize your code with less changes:
In your specific case you go through the whole array for each new found entry although all previous entries have already been processed so it should be possible to opimize further by passing the current index to findIndexes:
function findIndexes(arr,val, fromIndex){
var node = [];
for(var i=fromIndex,len=arr.length;i<len;i++){
if(arr[i] === val){
node.push(i);
}
}
return node;
}
Currrently your code has a O(n^2) complextity. This is caused by your outer loop of arr in process then a call to findIndexes which again loops through arr.
You can simplify this to an O(n) algorithm that loops through the array twice:
function process(arr) {
var result = [];
var counter = {}, counts = {};
var len = arr.length;
for(var i = 0; i < len; i++){
var value = arr[i];
counter[value] = 1;
counts[value] = (counts[value] || 0) + 1;
}
for(var i = 0; i < len; i++){
var value = arr[i];
if(counts[value] == 1) {
result.push(value);
} else {
result.push(value + "(" + counter[value]++ + ")");
}
}
return result;
}
Here's an example that doesn't use nested loops, and uses an object to store key information:
var obj = {};
// loop over the array storing the elements as keys in the object
// if a duplicate element is found, increment the count value
for (var i = 0, l = arr.length; i < l; i++) {
var key = arr[i];
if (!obj[key]) obj[key] = { count: 0, level: 0 };
obj[key].count++;
}
// remove all the key/values where the count is 1
// ie there are no duplicates
for (var p in obj) {
if (obj[p].count === 1) delete obj[p];
}
// for each element in the original array, increase its 'level'
// amend the element with the count
// reduce the count
for (var i = 0, l = arr.length; i < l; i++) {
var key = arr[i];
if (obj[key] && obj[key].count > 0) {
obj[key].level++;
arr[i] = key + '(' + obj[key].level + ')';
obj[key].count--;
}
}
DEMO

javascript splice causing lag in canvas

I have a simple running game where platforms scroll from right to left. These platforms are stored in an array, and when they are off screen I use array.splice(index, 1) to remove it. This however is causing an ever so slight lag on the exact second splice is called. I have also used Array.shift() but I can still see the slight dip in frame rate as this is called. Is there a better way to remove/destroy something?
for(var x = 0; x < platforms.length; x++){
var platform = platforms[x];
platform.x -= 10;
if(platform.x + platform.width < 0){
platforms.shift();
}
}
You could just not remove items from the array.
Use a fixed size array instead (large enough to store all the items you need) and flag as canceled the items you don't want to render anymore, you could reuse those flagged slots later.
Or you could directly overwrite the elements if the domain of your problem allows it.
[EDIT]
Some more considerations in response to the comments:
The evaluations of additional flag are computations stable in time, meaning that you can foresee how much time they will need and see if they fit the frame to render at a certain frame rate. Array.splice on the other hand could trigger garbage collection and that could be some order of magnitude longer than other language control flow constructs.
Garbage collection is an intensive task and should be avoided at all costs in the main loop of a game to achieve a fluid framerate. There are some resources and other questions here on SO which elaborate on this point, for example: http://buildnewgames.com/garbage-collector-friendly-code/
shift and splice are "slow" functions. They possibly rebuild your whole array.
Imagine having an area with 1000 items. A shift could possibly be 'create a new array with all items, except the first'. If your first 100 items now result in a shift, you rebuild 100 arrays, with 900-1000 items, which will result in about 100.000 inserts, 100 new array allocations.
for(var i = 0; i < array.length; i++)
{
if (array[i] == ....)
{
var newArray = new Array(array.length - 1);
for(var o = 1; o < array.length; o++)
newArray[o - 1] = array[o];
array = newArray
}
}
worst case scenario, with a length of 1000, this will result in:
for ( i = 0 to 1000 )
for ( o = i to 1000 )
recreate the array
so that would be 0.5million iterations and recreations of the array. While this could be fixed with either 1 iteration (dynamicly sized array) or with 2 passes (fixed sized array):
// dynamic size
var newArray = new Array();
for(var i = 0; i < array.length; i++)
{
if (array[i] != ....)
newArray.push(array[i]);
}
array = newArray;
// fixed size
var cnt = 0;
for(var i = 0; i < array.length; i++)
if (array[i] != ....)
cnt++;
var newArray = new Array(cnt);
for(var i = 0, o = 0; i < array.length; i++)
if (array[i] != ....)
newArray[o++] = array[i];
array = newArray;
and another simple optimization for your for loops (which obviously wont work if you modify the array in the for loop):
for(var i = 0, l = array.length; i < l; i++)
(yes, i am aware that some numbers may be off. but it gets the point across.)

Categories

Resources