I have this:
map = ranks.map((row, r) => (
row.map((rank, i) => {
return [element(r, i, state, rank, toggled, onClick)];
})
));
It maps through a 2-dimentional array.
After each row, I'd like to insert <div class="clearfix"></div>.
I think, if I could somehow get the last index for each row, so I will be able to use it in the row map callback. Can someone show me how to do it?
Try something like:
row.map((rank, i, row) => {
if (i + 1 === row.length) {
// Last one.
} else {
// Not last one.
}
})
Old answer:
const rowLen = row.length;
row.map((rank, i) => {
if (rowLen === i + 1) {
// last one
} else {
// not last one
}
})
As LeoYuan answered, this is the correct answer, but it can be a bit improved.
map accepts a function with a third parameter, which is the iterated array itself.
row.map((rank, i, arr) => {
if (arr.length - 1 === i) {
// last one
} else {
// not last one
}
});
or in a bit shorter version, using an object destructuring (thanks Jose from the comments):
row.map((rank, i, {length}) => {
if (length - 1 === i) {
// last one
} else {
// not last one
}
});
Using an arr.length instead of row.length is a better and correct approach for several reasons:
When you mix scopes, it may lead for an unexpected bugs, especially in a poorly written or poorly designed code. In general, it is always a good way to avoid mixing between scopes when possible.
When you like to provide an explicit array, it will work as well. E.g.
[1,2,3,4].map((rank, i, arr) => {
if (arr.length - 1 === i) {
// last one
} else {
// not last one
}
});
If you like to move the callback outside of the map scope (mainly for a better performance), it will be wrong to use row.length as it is out of scope. E.g. in the OP case:
const mapElement = (rowIndex, state, toggled, onClick) => {
return (rank, i, arr) => {
let lastIndex = arr.length - 1;
return [element(rowIndex, i, state, rank, toggled, onClick, lastIndex)];
};
};
map = ranks.map((row, r) => row.map(mapElement(r, state, toggled, onClick)));
Fewer lines of code with the same results
row.map((rank, i, {length}) => (
//last element
if(i + 1 === length){
}
));
A slight improvement on the accepted answer:
const lastIndex = row.length - 1;
row.map((rank, i) => {
if (i === lastIndex) {
// last one
} else {
// not last one
}
})
This removes the arithmetic from inside the loop.
A shorter method would be to use .map combined with ternary operator, like this.
const positions = ["first", "second", "third", "fourth"]
positions.map((x, index, array) => {
index === array.length -1
? console.log("this is the last item in the array")
: console.log( x)
}
//////////// explanation
x ### returns the current element .map is looping through
index ### returns the index(location of item in an array) of the current element.
array ### return the same element we are looping through so if we use sth like this
["first", "second", "third", "fourth"].map...
we'll still get the array we're looping through
array.length - 1 ### gives us the length of the array and - 1 gives us the index of the last element in the array.
simplify answer above
const array = ['apple','orange','banana'];
array.map((element, index) => (index === array.length - 1) ? \`${element}.\` : \`${element},\`);
you can check last index with your array's length. here is a logic
var randomnumber = Math.floor(Math.random() * (100 - 10 + 1)) + 10
console.log("your last index is dynamic, ehich is ",randomnumber-1);
let arry = [];
for (i=1;i<randomnumber;i++){
arry.push(i)
}
arry.map((data,index)=>{
if(index == arry.length-1 ){
console.log("last index data ",data)
}
else{
console.log("remain data ",data)
}
})
console.log("your last index is dynamic, which is ",randomnumber-1);
this is also works in dynamic arry changes..
it is a too simple technique which i use .. :-)
const array = ['apple','orange','banana'];
array.map((element, index) => {
//Last element
if (index === array.length - 1) {
return `${element}.`;
}
//Another elements
return `${element}, `;
})}
Will return apple, orange, banana.
Perhaps the most concise way (although a little "dirty" – you can get some ESLint errors and TypeScript also might not be happy about that) to access the length property in array.map() is to pull it out (by destructuring) of the third callback argument (which is the array we are mapping over) and then assign a new property e. g. lastIndex, which value is being derived from that previously pulled out length:
let list = ["Alice", "Bob", "Cedrick", "David", "Emily"]
let mapped = list.map((item, i, {length, lastIndex = length - 1}) => {
return i === lastIndex ? "lastitem: " + item : item
})
console.log(mapped)
Related
The array looks like:
var test = [
{
Time: new Date(1000),
psi:100.0
},
{
Time: new Date(1000),
psi:200.0
},
{
Time: new Date(2000),
psi:200.0
}
]
The function looks like (the function was copied from some online resource, couldn't find the exact reference.)
function uniqTimetable(nums){
console.log(nums); //log#1
var length = nums.length;
var count = 0;
for (var i =0; i< length-1; i++){
if (nums[count].Time.getTime() !== nums[i+1].Time.getTime()){
count ++;
nums[count] = nums[i+1];
}
}
nums.length = count + 1;
console.log(nums); // log #2
}
uniqTimetable(test);
console.log(test);// log #3
Are there any problems of
copy one object to the other array member by this linenums[count] = nums[i+1]
rescale the array length by this linenums.length = count + 1
?
With electron/node.js, the output looks a bit weird.
In log#1, it shows the array length is 2 instead of 3. Something seems wrong with the function. Any suggestions welcome.
Thanks in advance.
If I understood the problem, you can solve it in one line function:
const test = [{
Time: new Date(1000),
psi: 100.0
},
{
Time: new Date(1000),
psi: 200.0
},
{
Time: new Date(2000),
psi: 200.0
}
]
const unique = test.filter(({Time}, i, array) =>
!array.find((item, j) => item.Time.getTime() === Time.getTime() && j > i));
console.log(unique);
(I assumed psi is not relevant)
It uses find and filter array's methods.
function removeDuplicates(myArr, prop) {
return myArr.filter((obj, pos, arr) => {
return arr.map(mapObj => mapObj[prop]).indexOf(obj[prop]) === pos;
});
}
removeDuplicates(test,"Time")
Using the filter function of javascript, to return the List of only unique elements.
I like #Akin's answer! But unfortunately the .indexOf() function does not work for Date objects with the same value, since each object is still considered to be different and the .indexOf() function will always find the index of the Date object itself and never another "copy". To overcome this I convert the Date object back to milliseconds before collecting the values in an array (tst). I do this with myArr.map(mapObj => mapObj[prop].getTime()) before I go into the .filter function.
As the .getTime() method will only work for Date objects it does not make sense to keep the property prop as an argument. Instead I hardcoded the .Time property into the code.
Edit:
By coercing a numerical data type with a unary operator + for the .Time property I can leave out the .getTime() method which will be applied implicitly.
var test = [{Time: new Date(1000), psi:100.0},
{Time: new Date(1000), psi:200.0},
{Time: new Date(2000), psi:200.0}];
function Cars10m_remDups(myArr) {
let tst=myArr.map(o=>+o.Time);
return myArr.filter((o, i)=>tst.indexOf(+o.Time)===i);
}
// for comparison: --> will list all three objects!
function Akin_remDups(myArr, prop) {
return myArr.filter((obj, pos, arr) => {
return arr.map(mapObj => mapObj[prop]).indexOf(obj[prop]) === pos;
});
}
// Zero's one-liner works too, here: my shortened version
const Zero_remDups = myArr => myArr.filter(({Time}, i, array) =>
!array.find((item, j) => +item.Time-Time==0&&i>j));
// also: with "i>j" I pick the first unique (Zero chose the last)
console.log('Cars10m:',Cars10m_remDups(test));
console.log('Akin:',Akin_remDups(test,"Time"));
console.log('Zero:',Zero_remDups(test));
.as-console-wrapper { max-height: 100% !important; top: 0; }
How can I make a search function using regEx?
I have some code but can't post it at the moment due to my computer being very broken and annoying, I will try again tomorrow!
This is not really what would be called combinations, but permutations.
The idea is to use recursion for getting the result for a shorter array, i.e. the one that lacks the first element.
Then take all permutations you get back from the recursive call, and insert the left-out value in each possible index.
When input has duplicates, then you need to stop inserting the left-out value as soon as you find that same value preceding the insertion spot.
Here is how that looks:
function scramble(array) {
if (array.length == 0) {
return [[]];
}
let results = [];
// solve the problem for a shorter array (first value excluded), and iterate:
for (let perm of scramble(array.slice(1))) {
// add the missing element in each possible position:
for (let i = 0; i < array.length; i++) {
// next IF is only needed when input has duplicates, and
// output should not repeat same array:
if (i && array[0] === perm[i-1]) break;
results.push(perm.slice(0, i).concat(array[0], perm.slice(i)));
}
}
return results;
}
let array = ["I", "am", "coding", "am"];
console.log(scramble(array));
Without the inner if, an input with duplicate values will produce duplicate arrays. If this is not desired, then the if is needed.
You could iterate and get a flat array of the mapping of the value with the result of the nested calls.
function permutation(array) {
return array.length === 1
? [array]
: array.flatMap((v, i) => permutation([
...array.slice(0, i),
...array.slice(i + 1)
]).map(a => [v, ...a]));
}
permutation(["I", "am", "coding"]).map(a => console.log(...a));
I have a string:
"5 * ((6 + 2) - 1)"
I need to find the deepest pair of parentheses and their contents.
I've googled a lot and I can't find anything specific to finding the index. A lot of solutions found how many levels there are, and things like that, but nothing was really helpful. I was thinking of counting the layers, and then using a loop to solve and repeat solving until done, but it seems like this would be really slow.
I have no idea where to start, so I haven't written any code yet.
I want a function to return 5, the string index of the deepest set of parentheses. I also need to do the same for the deepest ")", since I need the pair. Example:
const deepestPair = (str) => {
// Find deepest pair of parentheses
}
deepestPair("(2(5)4)(3)") // Returns [2, 4], the indexes of the deepest open/close parentheses
You could check opening and closing parentheses and use a counter for getting the most nested indices.
const deepestPair = str => {
var indices,
max = 0,
count = 0,
last;
[...str].forEach((c, i) => {
if (c === '(') {
last = i;
count++;
return;
}
if (c === ')') {
if (count > max) {
indices = [last, i];
max = count;
}
count--;
}
});
return indices;
}
console.log(deepestPair("(2(5)4)(3)")); // [2, 4]
You can use RegExp ([(])[^()]+[)] to match ( followed by one or more characters that are not ( or ) and closing ), /[)]/ to match closing parenthesis, return indexes of matches
const deepestPair = (str, index = null) =>
[index = str.match(/([(])[^()]+[)]/).index
, str.slice(index).match(/[)]/).index + index]
console.log(deepestPair("(2(5)4)(3)"));
Here is a simple way to get the deepest pair using two stacks. It also returns the depth of the pair in a structure, with the open and close indices.
It uses a singles stack to hold the open parenthesis found so far, and another stack (pairs) for matched parenthesis.
Each time a closing parenthesis is found, the last open parenthesis is popped from the singles stack and put in the pairs.
Then you just have to sort this pairs stack using the depth property and get the first item.
const deepestPair = str => {
const singles = [];
const pairs = [];
[...str].forEach((c, i) => {
if (c === '(') {
singles.push({ depth: singles.length + 1, open: i });
} else if (c === ')' && singles.length) {
pairs.push({ ...singles.pop(), close: i });
}
})
pairs.sort((a, b) => b.depth - a.depth);
return pairs.length ? pairs[0] : {};
};
console.log(deepestPair('(2(5)4)(3)'));
console.log(deepestPair('(2(5)(1)(11(14))4)(3)'));
If you want to get an array as the result you can replace the last line by this:
return pairs.length ? [pairs[0].open, pairs[0].close] : [];
I was asked in an interview to write a program/algo to sort an array of number using recursion.
Though I vaguely answered it, I tried and came up with following code:
You can use following JSFiddle link to play around.
function sort(arr) {
if (arr.length === 2) {
const v1 = arr[0];
const v2 = arr[1];
const isGreater = (
(isString(v1) && isString(v2) && v1.toString().toLocaleCompare(v2) > 0) ||
(isNumber(v1) && isNumber(v2) && v1 > v2)
);
return isGreater ? [ v2, v1 ] : [ v1, v2 ];
} else {
const last = arr.pop();
const ret = sort(arr);
const newLast = ret.peekLast();
if (newLast < last) {
return [ ...ret, last ];
} else {
return sort( [ last, ...ret ] );
}
}
}
function isString(value) { return typeof value === 'string'; }
function isNumber(value) { return Number.isFinite(value); }
Array.prototype.peekLast = function () { return this.slice().pop(); }
//console.log(sort([1,2,3,4,5]))
console.log(sort([5,4,3,2,1]))
The algo I implemented is:
Take the array and check if its length is greater than 2.
If yes,
Remove last element and store it in a variable.
Again call same function without last element till it has 2 items.
Accept array returned from recursive call and peek the last element.
If newLast value is greater than previousLast
Push previousLast as first element and again call itself with this array.
If not, push previousLast to array and return it.
Else,
For number and string check equality and return correct order.
For anything else, return same value
Question is, is there a better way to implement (algo wise)?
Note: I'm not expecting code improvements. Objective of this question is improvement in algo part or any general stuff I have missed.
I also know, current code does not support:
Sort order. It will sort ascending only.
May break for Date objects, and does not support Objects in general.
Thanks!
I think most interviewers would expect you to respond with quicksort or merge sort (or both) given that question. Of the two, quicksort, is easier to remember and recreate in a pinch because the merge step of merge sort is easy to mess up.
Quicksort is a really beautiful algorithm and is a natural fit for javascript's functional tools. It is worth really understanding if you'll be doing interviews:
const arr = [6, 1, 5, 3, 9, 6, 7, 10, 16, 4, 0, 12, 2]
function qsort(arr){
if (arr.length < 2) return arr
// choose a pivot, p
// the choice of pivot can effect worst-case performance
// for this, we'll just use the first element.
const [p, ...rest] = arr
// partition array into element greater and lesser that the pivot
// this can be optimized so you don't loop through the array twice
const low = rest.filter(n => n <= p)
const high = rest.filter(n => n > p)
// recurse on both partitions and reassemble as recursion unwinds
return [...qsort(low), p, ...qsort(high)]
}
console.log(qsort(arr).join(', '))
I see a vein of intermediate value creation that is not inconsequential.
peekLast calls Array.prototype.slice which makes a copy of the array. You copy an entire array just to return the last element.
Array.prototype.peekLast = function () { return this.slice().pop(); }
Array.prototype.peekLast = function () { return this[this.length]; }
This gives you the same result every time without the need to copy.
Use of spread arguments in expressions like [ ...arr, x ] copies arr entirely.
arr.concat([ x ]) does the same thing without making copy (or mutation) of arr
You call peekLast and use ...x once per element in the input. Calling sort on a list of just 100 items will copy over 10,000 elements, for these operations alone. A list of just 1,000 items will copy over 1,000,000 elements. Room for algorithm improvment? For sure.
Mark Meyer starts you off on the right foot. If you're going to use recursion, it's best writing your program in functional style, as it will yield the best results. Mixing imperative style (statements, mutations, reassignments, other side effects, etc) with recursion is a recipe for a migraine.
Mark's algorithm, however great a "code improvement", your question is asking for "algorithm improvements". Under this lens, Mark's algorithm suffers from similar intermediate value creation by use of many ...x expressions.
Another lurking offense is the double use of .filter on the same array, rest. This creates an inefficient process as it iterates entirely through rest two (2) times per element. This is a symptom of reaching for low-hanging built-in functions that do close to what you want, but not exactly what you want. A better function would iterate through the array once and return both results.
The inefficiencies in Mark's program are mostly forgivable because of the dramatic improvement in code quality. His program is much more readable than yours because he's using functional style, which is where recursion comes from. The inefficiencies are also very easy to fix, so maybe that's an exercise for you?
Let's see if that gets your brain going. We'll see what answers other people submit before smothering you with too much information.
Your code will fail if we have duplicate elements because of this line.
if (newLast < last) {
It will go into infinite recursion
Refer the snippet with the duplicate array passed as input
function sort(arr) {
if (arr.length === 2) {
const v1 = arr[0];
const v2 = arr[1];
const isGreater = (
(isString(v1) && isString(v2) && v1.toString().toLocaleCompare(v2) > 0) ||
(isNumber(v1) && isNumber(v2) && v1 > v2)
);
return isGreater ? [ v2, v1 ] : [ v1, v2 ];
} else {
const last = arr.pop();
const ret = sort(arr);
const newLast = ret.peekLast();
debugger;
if (newLast < last) {
return [ ...ret, last ];
} else {
return sort( [ last, ...ret ] );
}
}
}
function isString(value) { return typeof value === 'string'; }
function isNumber(value) { return Number.isFinite(value); }
Array.prototype.peekLast = function () { return this.slice().pop(); }
//console.log(sort([1,2,3,4,5]))
console.log(sort([3,3,5,2]))
this one work for me to sort an array recursively:
var array = [3,1,8,2,4,9,16,28];
const sum = (arr, i=0)=> {
if(i === arr.length) return arr;
if(arr[i+1] < arr[i]){
const x = arr[i+1];
arr[i+1] = arr[i];
arr[i] = x;
}
return sum(arr,i+1);
}
console.log(sum(array))
function swap(arr, firstIndex, secondIndex){
let a= arr[firstIndex];
arr[firstIndex] = arr[secondIndex];
arr[secondIndex] = a;
return arr;
}
function sortArr(arr, index=0){
if(index == arr.length) return arr;
for(let i=0;i<arr.length; i++){
if(arr[i] > arr[i+1]){
arr = swap(arr, i, i+1);
}
}
return sortArr(arr, index+1);
}
console.log(sortArr([4,1,3,2,0]));
function quicksort(num){
if (num.length < 2){
return num
}
let pivot = num[0];
let slicedArr = num.slice(1);
let left = [];
let right = [];
for(let i = 0; i < slicedArr.length; i++){
if(slicedArr[i] <= pivot){
left.push(slicedArr[i])
}else{
right.push(slicedArr[i])
}
}
return [...quicksort(left), pivot, ...quicksort(right)]
}
I've got an array that I would like to remove some elements from. I can't use Array.prototype.filter(), because I want to modify the array in place (because it saves a memory allocation and, more important for me, makes the code more simple in my use case). Is there an in-place alternative to filter that I can use, maybe analogously to how Array.prototype.forEach() can be used as an in-place variant to Array.prototype.map()?
Edit: Minimum example upon request:
function someCallback(array) {
// do some stuff
array.filterInPlace(function(elem) {
var result = /* some logic */
return result;
})
// do some more stuff
}
Is there an in-place alternative to filter
No, but it's not hard to write your own. Here is an approach which squeezes out all the values which fail a condition.
function filterInPlace(a, condition) {
let i = 0, j = 0;
while (i < a.length) {
const val = a[i];
if (condition(val, i, a)) a[j++] = val;
i++;
}
a.length = j;
return a;
}
condition is designed to have the same signature as the callback passed to Array#filter, namely (value, index, array). For complete compatibility with Array#filter, you could also accept a fourth thisArg parameter.
Using forEach
Using forEach has the minor advantage that it will skip empty slots. This version:
Compacts arrays with empty slots
Implements thisArg
Skipps the assignment, if we have not yet encountered a failing element
function filterInPlace(a, condition, thisArg) {
let j = 0;
a.forEach((e, i) => {
if (condition.call(thisArg, e, i, a)) {
if (i!==j) a[j] = e;
j++;
}
});
a.length = j;
return a;
}
a = [ 1,, 3 ];
document.write('<br>[',a,']');
filterInPlace(a, x=>true);
document.write('<br>[',a,'] compaction when nothing changed');
b = [ 1,,3,,5 ];
document.write('<br>[',b,']');
filterInPlace(b, x=>x!==5);
document.write('<br>[',b,'] with 5 removed');
You could use the following:
array.splice(0, array.length,...array.filter(/*YOUR FUNCTION HERE*/))
Explanation:
Splice acts in place
First argument means we start at the start of the array
Second means we delete the entire array
Third means we replace it with its filtered copy
The ... is the spread operator (ES6 only) and changes each member of the array into a separate argument
What you could use
Array#filter returns an array with the same elements, but not necesserily all.
Array#map returns something for each loop, the result is an array with the same length as the source array.
Array#forEach returns nothing, but every element is processed, like above.
Array#reduce returns what ever you want.
Array#some/Array#every returns a boolean value.
But nothing from above is mutating the original array in question of length in situ.
I suggest to use a while loop, beginning from the last element and apply splice to the element, you want to remove.
This keeps the index valid and allows to decrement for every loop.
Example:
var array = [0, 1, 2, 3, 4, 5],
i = array.length;
while (i--) {
if (array[i] % 2) {
array.splice(i, 1);
}
}
console.log(array);
If you are able to add a third-party library, have a look at lodash.remove:
predicate = function(element) {
return element == "to remove"
}
lodash.remove(array, predicate)
The currently selected answer works perfectly fine. However, I wanted this function to be a part of the Array prototype.
Array.prototype.filterInPlace = function(condition, thisArg) {
let j = 0;
this.forEach((el, index) => {
if (condition.call(thisArg, el, index, this)) {
if (index !== j) {
this[j] = el;
}
j++;
}
})
this.length = j;
return this;
}
With this I can just call the function like so:
const arr = [1, 2, 3, 4];
arr.filterInPlace(x => x > 2);
// [1, 2]
I just keep this in a file called Array.js and require it when needed.
A slightly simplified TypeScript variant of user663031's answer:
function filter_in_place<T>(array: Array<T>, condition: (value: T) => boolean)
{
let next_place = 0;
for (let value of array)
{
if (condition(value))
array[next_place++] = value;
}
array.splice(next_place);
}
Using splice() instead of setting the length results in a 1.2x speedup for 1400000 iterations on Chrome 76.