Get minimum and maximum of object property names that are integers - javascript

UPDATED (formulated the problem wrong, see note below)
I have an object that has a set of properties that are named with numbers as shown in the example. The 'numbered names' are not necessarily consecutive, nor do I know where they start or end. I do know that other properties will not be named with numbers.
I know that myObject["propName"] is the same as myObject.propName, but I deliberately write it in the first way because myObject.0 looks weird and doesn't get recognized by all editors.
How do I get the min- and maximum array index?
So in a situation like this
myObject["0"] = undefined
myObject["1"] = {}
myObject["2"] = undefined
myObject["3"] = {}
myObject["4"] = {}
myObject["5"] = undefined
myObject["someOtherProperty"] = {}
would give me this
minIndex(myObject) == 1
maxIndex(myObject) == 4
To all the answers before this edit
Thanks for your replies. I shouldn't have posted this question in a hurry and should have re-read it before committing. It was late and I was in a hurry. My apologies.
By actually seeing my wrong statement (using an array instead of an object) I think that, based on answers for my reformulated problem, I might need to rewrite my code to use an array instead of an object. The reason I'm using an object rather then an array is material for another question.
Efforts so far
I have tried finding a way of converting the property names to an array and then looping through them, but that has proven cludgy. I'm kind of looking for a less error-prone and elegant way.

Edit: Aha! Now the problem becomes more interesting.
Solution 1: Let's solve this in one shot, shall we? For max:
function maxIndex(obj){
var max = -1;
for(var i in myObject){
var val = parseInt(i);
if(isFinite(val)){
if(typeof obj[val] !== 'undefined' && val > max){
max = val;
}
}
}
return max;
}
I think you can convert this to min on your own ;)
Solution 2: Here I'll your object back into what we originally thought it was, in case you really loved one of the other solutions. Then the rest of the answer applies.
function convertObject(obj){
var output = [];
for(var i in myObject){
var val = parseInt(i);
if(isFinite(val)){
output[val] = obj[i]; //Gotta love JS
}
}
return output;
}
Continue as planned!
To find the smallest, begin at the bottom and work your way up until you find it.
function minIndex(myArray){
for(var i = 0; i < myArray.length; i++){
if(typeof myArray[i] !== 'undefined')
return i;
}
}
To get the biggest, start at the top.
function maxIndex(myArray){
for(var i = myArray.length - 1; i >= 0; i--){
if(typeof myArray[i] !== 'undefined')
return i;
}
}
Both are worst case O(n). You can't really do better because the whole array could be empty, and you'd have to check every element to be positive.
Edit: As is mentioned, you can also check if something is not undefined by simply writing if(myArray[i]). Whatever suits your fancy.

var myObject = {};
myObject["0"] = undefined;
myObject["1"] = {};
myObject["2"] = undefined;
myObject["3"] = {};
myObject["4"] = {};
myObject["5"] = undefined;
myObject["someOtherProperty"] = {};
var keys = Object.keys(myObject).map(Number).filter(function(a){
return isFinite(a) && myObject[a];
});
var min = Math.min.apply(Math, keys);
var max = Math.max.apply(Math, keys);
console.log(min, max); //Logs 1 and 4
Documentation and compatibility information for all:
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/map
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/filter

Try looping through the array until you find the 1st non-undefined element.
function minIndex(arr){
for(var i = 0, len = arr.length; i < len; i++){
if(arr[i] !== undefined){
return i;
}
}
}
For max index, do the same thing, except in reverse.
function maxIndex(arr){
for(var i = arr.length-1, len = 0; i >= len; i--){
if(arr[i] !== undefined){
return i;
}
}
}

Min:
for(var i = 0; i < myArray.length; i++) {
if(myArray[i] != undefined) {
return i;
}
}
Max:
for(var i = myArray.length-1; i >= 0; i--) {
if(myArray[i] != undefined) {
return i;
}
}

try something like this:
function minIndex(var array){
for(var i = 0; i < array.length; i++)
{
if(typeof array[i] != "undefined")
return i;
}
return null;
}
function maxIndex(var array){
var returnIndex = -1;
for(var i = 0; i < array.length; i++)
{
if(typeof array[i] != "undefined")
returnIndex = i;
}
if(returnIndex !== -1) return returnIndex;
else return null;
}

this takes advantage of the fact that for..in only iterates over defined elements, and uses the index:
function minIndex(arr){ for(el in arr){return el} }
function maxIndex(arr){var v; for(el in arr){v = el}; return v }
CAVEATS:
The second function is not very efficient though, since it loops through the entire array.
This wont work if you are EXPLICITLY setting the undefined indexes.

var max=0;
var min=myArray.length;
for (var i in myArray)
if (myArray[i]!==undefined)
{
max=Math.max(i, max);
min=Math.min(i, min);
}

Related

How to analyse complexity of an Algorithm that contains hidden loops made by external function or method?

First of all, I would like to apologize in case my title is not concise as it should be, but my point is, if you take a look at the following code which is selection sort algorithm, it's obvious for someone to analyze its complexity.
module.exports = function (arr) {
var temp;
for (var i = 0; i < arr.length; i++) {
var iTh = i;
for (var j = i+1; j < arr.length; j++) {
if (arr[j] < arr[iTh]) {
iTh = j;
}
}
temp = arr[i];
arr[i] = arr[iTh];
arr[iTh] = temp;
}
return arr;
}
But what if an algorithm contains hidden loops which are provided by particular language's functions or methods. For instance these two functions are both reversing a string, and they have JavaScript methods which have complexity behind them too.
So! How can someone analyze the complexity of these two and pick the optimal one? Or they don't qualify to be algorithms?
First Reverse
exports.reverse1 = function (str) {
if (str == undefined || str.length) {
return 0;
}
let collector = [];
for (var i = str.length; i >= 0; i--) {
collector.push(str.charAt(i));
}
return collector.join("");
}
Second Reverse
exports.reverse2 = function (str) {
if (str == undefined || str === "") {
return 0;
}
return str.split("").reverse().join("");
}

Missing letters freecodecamp

Actually I found an answer a few minutes ago.
But I found something strange.
This is my answer for 'Missing letters' in freeCodeCamp challenges.
function fearNotLetter(str) {
var string;
for (i=0;i<str.length;i++) {
if(str.charCodeAt(i)+1 < str.charCodeAt(i+1)){
string = String.fromCharCode(str.charCodeAt(i)+1);
}
}
return string;
}
When I change < operator in if statement into != (not same), it doesn't work!
For me, it seems that != works exactly same as < operator does.
(Because 'not same' can mean something is bigger than the other.)
What is the difference between < and != in the code above?
Your code has a small defect that works when you use < but not !=.
If you see str.charCodeAt(i+1); this code is checking one spot past the end of the string on the last iteration and will return a NaN result.
If I provide the string "abce" it will check if f is < NaN. I believe NaN can't be compared to f's value so it doesn't go into the if statement. So it will keep the missing letter d that was found in the previous iterations which is stored in your string variable.
However, if you provide the !=, then with the same scenario it knows f != NaN and goes into the if statement. This then overwrite the actual missing letter and fails your FCC test case because it is replacing the missing d with f in your string variable.
To fix your code, simply change the for loop to end one iteration before the length of the string.
for (i = 0; i != str.length-1; i++) {
}
This is my method without using .charCodeAt() function :)
function fearNotLetter(str) {
var ind;
var final = [];
var alf =['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'];
str = str.split('');
ind = alf.splice(alf.indexOf(str[0]),alf.indexOf(str[str.length-1]));
for(var i=0;i<ind.length;i++){
if(str.indexOf(ind[i]) == -1){
final.push(ind[i]);
}
}
if(final.length != 0){
return final.join('');
}
return;
}
fearNotLetter("bcef");
My solution:
function fearNoLetter(str){
var j= str.charCodeAt(0);
for(var i=str.charCodeAt(0); i<str.charCodeAt(str.length-1); i++){
j = str.charCodeAt(i - str.charCodeAt(0));
if (i != j){
return String.fromCharCode(i);
}
}
}
My solution:
function fearNotLetter(str) {
let y = 0;
for (let i = str.charCodeAt(0); i < str.charCodeAt(str.length - 1); i++) {
if (str.charCodeAt(y) != i) {
return String.fromCharCode(i);
}
y++;
}
return;
}
console.log(fearNotLetter("ace"));
function fearNotLetter(str) {
let alpha = "abcdefghijklmnopqrstuvwxyz";
let alphabet = []
for(let j = 0; j< alpha.length; j++){
alphabet.push(alpha[j])
}
if (alphabet.length == str.length){
let result = undefined;
return result
}else{
const start =alphabet.indexOf(str[0])
let end = (str.length)-1
const stop = alphabet.indexOf(str[end])
const finish = alphabet.slice(start,stop)
let result = finish.filter(item => !finish.includes(item) || !str.includes(item))
result = String(result)
return result
}
return result
}
console.log(fearNotLetter("abcdefghijklmnopqrstuvwxyz"));

how do I find the id of the minimum value of an array?

I know that you can have the minimum value of an array by typing
var min = Math.min.apply(null, array)
but this will return the smallest value of an array and not the id of this one
for exemple if I have these values:
array[1] = 24;
array[2] = 45;
I want it to return 1 (the ID holding the minimum value) but idk how to do, could someone help me with this issue please?
var index = array.indexOf(Math.min.apply(null, array));
You can use Array#reduce() to get the smallest number, while avoiding holes in the Array if needed.
array.reduce(function(obj, n, i) {
if (n < obj.min)
obj.i = i;
return obj;
}, {min:Infinity,i:-1}).i;
Or if performance and compatibility is a concern, you could just loop.
var res = -1;
var min = Infinity;
for (var i = 0; i < array.length; i++) {
if ((i in array) && array[i] < min) {
min = array[i];
res = i;
}
}
You can do it like this:
var id = array.indexOf(Math.min.apply(null, array));
Once you've got the value, you can use indexOf to get the index, like this:
var index = array.indexOf(Math.min.apply(null, array));
You should be aware that indexOf was only recently included in JavaScript (ES5/JS 1.6 to be precise) so you may want to find some wrapper for it if the function does not exist.
See the MDN for more information (which contains an example implementation of a backwards compatible function).
Just like the algorithm for finding the min value, but you have to track the minimum index as well
function minIndex(arr) {
if (!arr || arr.length === 0) {
return -1;
}
var min = arr[0];
var minIndex = 0;
for (var len = arr.length; len > 0; len--) {
if (arr[len] < min) {
min = arr[len];
minIndex = len;
}
}
return minIndex;
}
check out this fiddle

Most efficient way to merge two arrays of objects

I've already solved this out. However I'm looking for a faster solution since my variables has thousands of objects.
I have two arrays like this:
var full = [{a:'aa1',b:'bb1'},{a:'aa3',b:'bb2'},{a:'aa3',b:'bb3'},{a:'aa2',b:'bb3'}],
some = [{a:'aa1',b:'bb1'},{a:'aa3',b:'bb3'}];
I'm trying to flag in a new attribute called c in full if the object exist on some. Expected result:
[{a:'aa1',b:'bb1',c:true},{a:'aa3',b:'bb2'},{a:'aa3',b:'bb3',c:true},{a:'aa2',b:'bb3'}]
Some important tips:
some always has less elements than full
both arrays are sorted equal
My current approach is:
var getIndexByAB = function(arr, a,b){
var initialIndex = getIndexByAB.initialIndex || 0,
len = arr.length;
for(initialIndex; initialIndex < len ;initialIndex++ ){
var el = arr[initialIndex];
if( el.b === b && el.a === a ){
getIndexByAB.initialIndex = initialIndex;
return initialIndex;
}
}
return -1;
}
var len = some.length;
for(var i = 0; i < len ; i++){
var el=some[i],
index = getIndexByAB(full,el.a,el.b);
if(index > -1) full[index].c = true;
}
UPDADE: original solution improved using Juan comment.
Since they are sorted, you can just pass an index to start the search from, that will avoid the O(n^2). You were already doing it, but by storing the index in a global variable. Instead, you should pass it as an argument to getIndexByAB.
function getIndexByAB(arr, a,b , initialIndex){
// Was tracking last index by storing it in a global 'this.initialIndex'.
// 'this' points to 'window' in global functions. That's bad, it
// means this function can't be called on different arrays without
// resetting the global
// var initialIndex = this.initialIndex || 0,
initialIndex = initialIndex || 0;
var len = arr.length;
for(initialIndex; initialIndex < len ; initialIndex++ ){
var el = arr[initialIndex];
if( el.b === b && el.a === a ){
// Bad globals
// this.initialIndex = initialIndex;
return initialIndex;
}
}
return -1;
}
var len = some.length;
var lastValidIndex = 0;
for(var i = 0; i < len ; i++){
var el = some[i];
// Pass the index here, so it doesn't start from scratch
var index = getIndexByAB(full, el.a, el.b, lastValidIndex);
if(index > -1) {
full[index].c = true;
lastValidIndex = index;
}
}
By the way, if you do want a function to cache some values, here's how to do it avoiding globals. (Not that you should use it in this case)
var getIndexByAB = (function(){
// This will only be executed once, and is private
// to getIndexByAB (all invocations)
var lastGoodIndex = 0;
return function(arr, a,b, resetIndex){
if (resetIndex) {
lastGoodIndex = 0;
}
var len = arr.length;
for(var index = lastGoodIndex; index < len ; index++ ){
var el = arr[index];
if( el.b === b && el.a === a ){
lastGoodIndex = index;
return index;
}
}
return -1;
};
})();
Alternatively, you could achieve the following by caching it in getIndexByAB.initialIndex but it's not very elegant. The main reason for avoiding this is the fact that getIndexByAB.initialIndex can be modified by anybody else
Since the arrays are both sorted and some is strictly smaller than full, you could save some time by traversing both arrays at the same time with different indexes. As it is, you are traversing full to get the index of the matching element each time, so you have O(N^2) running time, but you only need to continue the search from the last element you matched.
Not as efficient as #Juan's answer (which takes advantage of the sorted nature, among other things), but I thought I'd still present my solution as it incidentally forced me to come up with a solution for cloning and comparing Javacript objects.
Utilities
// Create a copy of x without reference back to x
function clone(x){
return JSON.parse(JSON.stringify(x));
}
// Pass any number of arguments of any type. Returns true if they are all identical.
function areEqual(){
for(var i = 1, l = arguments.length, x = JSON.stringify(arguments[0]); i < arguments.length; ++i){
if(x !== JSON.stringify(arguments[i])){
return false;
}
}
return true;
}
Flagging function
// Your flagLabel being 'c'
function matchAndFlagWith(flagLabel,aFull,aSome){
var aFlagged = clone(aFull);
for(var i1 = 0, l1 = aSome.length, oSome; oSome = aSome[i1], i1 < l1; ++i1){
for(var i2 = 0, l2 = aFlagged.length, oFlagged; oFlagged = aFlagged[i2], i2 < l2; ++i2){
if(areEqual(oFlagged,oSome)){
oFlagged[flagLabel] = true;
}
}
}
return aFlagged;
}
Demo
http://jsfiddle.net/barney/p2qsG/

How can I search for a value in an array and delete just one of those values if 2 or more is found?

I have an array
var aos = ["a","a","a","b","b","c","d","d"];
I want to know if I can remove just 1 item if it finds 2 or more of the same value in the array. So for instance if it finds
"a", "a"
it will remove one of those "a"
This is my current code:
var intDennis = 1;
for (var i = 0; i < aos.length; i++) {
while (aos[i] == aos[intDennis]) {
aos.splice(i, 1);
intDennis++;
console.log(aos[intDennis], aos[i]);
}
intDennis = 1;
}
NOTE: My array is sorted.
Edited after better understanding of OP use-case.
Updated solution and fiddle test to incorporate suggestion from pst in comments.
(Not for nothing, but this method does not require the original array be sorted.)
Try this...
var elements = [];
var temp = {};
for (i=0; i<aos.length; i++) {
temp[aos[i]] = (temp[aos[i]] || 0) + 1;
}
for (var x in temp) {
elements.push(x);
for (i=0; i<temp[x]-2; i++) {
elements.push(x);
}
}
Fiddle Test
Because you said you have a sorted array, you only need to remove the second time a element is found. You only need one for.
The splice() function returns the removed element so, just use it to not remove more elements of that kind.
This solution is more clean and efficient.
var aos = ["a","a","a","b","b","c","d","d"];
var lastRemoved = "";
for (var i = 1; i < aos.length; i++) {
if (aos[(i-1)] == aos[i] && lastRemoved != aos[i]) {
lastRemoved = aos.splice(i, 1);
}
}
Code tested and working. Result: ["a", "a", "b", "c", "d"]
I don't believe there's any better way to do this on an unsorted array than an approach with O(n^2) behaviour. Given ES5 array-builtins (supported in all modern browsers, though not in IE prior to IE9), the following works:
aos.filter(function(value, index, obj) { return obj.indexOf(value) === index; })
UPDATED ANSWER TO REMOVE ONLY 1 DUPLICATE:
Assuming that each object will resolve to a unique String, here's a potential solution. The first time the object is detected, it sets a counter for that object to one. If it finds that object again, it splices that element out and increments the associated counter. If it finds that element more times, it will leave it alone.
var elements = {};
for (var i = 0; i < aos.length; i++) {
if(elements[aos[i]]){
if(elements[aos[i]] == 1){
aos.splice(i,1);//splice the element out of the array
i--;//Decrement the counter to account for the reduced array
elements[aos[i]]++;//Increment the count for the object
}
} else {
elements[aos[i]] = 1;//Initialize the count for this object to 1;
}
}
Here's the test fiddle for this.
I would not mutate the input -- that is, don't use splice. This will simplify the problem a good deal. Using a new array object here may actually be more efficient. This approach utilizes the fact that the input array is sorted.
Consider: (jsfiddle demo)
var input = ["a","a","a","b","b","c","d","d"]
var result = []
for (var i = 0; i < input.length; i++) {
var elm = input[i]
if (input[i+1] === elm) {
// skip first element (we know next is dup.)
var j = i + 1
for (; input[j] === elm && j < input.length; j++) {
result.push(input[j])
}
i = j - 1
} else {
result.push(elm)
}
}
alert(result) // a,a,b,c,d
Happy coding.
Replace === with a custom equality, as desired. Note that it is the first item is omitted from the output, which may not always be "correct".
REVISED EXAMPLE
function removeDuplicate(arr) {
var i = 1;
while(i < arr.length) {
if(arr[i] == arr[i - 1]) {
arr.splice(i, 1);
}
while(arr[i] == arr[i - 1] && i < arr.length) {
i += 1;
}
i += 1;
}
return arr;
}
alert(removeDuplicate(["a","a","a","b","b","c","d","d"]));

Categories