I want to remove all the null values between the first number and the end number.
My code seems far too complicated.
Love to see some more flexible minds at it.
let values = [null, null, null, 1, 2, null, 3, null, 4, null, null, 5, 6, 7, null, null, null, null];
let startIndex = values.findIndex(n => (n !== null))
let endIndex = values.length - 1;
for ( ; endIndex > 0; endIndex--) {
if (values[endIndex] !== null) break;
}
let arrayCopy = values.slice();
for(let i = endIndex; i > startIndex; i--) {
if (values[i] === null) {
arrayCopy.splice(i, 1);
}
}
console.log(arrayCopy)
Quick and dirty, sure it can be done better
var values = [null, null, null, 1, 2, null, 3, null, 4, null, null, 5, 6, 7, null, null, null, null];
var nonNull = values.filter(value => value !== null);
var result = [...values.slice(0, values.indexOf(nonNull[0])), ...nonNull, ...values.slice(values.lastIndexOf(nonNull[nonNull.length - 1]) + 1)];
console.log(result);
I used a filter taking index or null values into account, it is certainly clearer IMO.
If your array is "very large", it might be interesting to find another way to compute the endIndex, but if you don't have performance problems, I think you can keep this part of your code as it is.
let values = [null, null, null, 1, 2, null, 3, null, 4, null, null, 5, 6, 7, null, null, null, null];
let startIndex = values.findIndex(n => (n !== null))
let endIndex = values.length - 1;
for ( ; endIndex > 0; endIndex--) {
if (values[endIndex] !== null) break;
}
let arrayCopy = values.filter((v, i) => i < startIndex || i > endIndex || v !== null);
console.log(arrayCopy)
This approach use reduce function to find the number of nulls in the at the start and at the end of the array, and then to add counted nulls before and after the non null elements.
let values = [null, null, null, 1, 2, null, 3, null, 4, null, null, 5, 6, 7, null, null, null, null];
var reduceFn = function(a,b){
if (!a.finished && b === null){
a.nullCount++;
}
if (b !== null){
a.finished = true;
}
return a;
};
var start = {finished : false, nullCount:0};
values.reduce(reduceFn,start);
var end = {finished : false, nullCount:0};
values.slice().reverse().reduce(reduceFn,end);
result = Array(start.nullCount).fill(null);
result.push.apply(result,values.filter(v => v !== null));
result.push.apply(result,Array(end.nullCount).fill(null));
console.log(result)
Related
I have got the following code that returns an object based on a filter
i want to convert this to functional programming using map, filter.
var records_object = {
"record": [
"analog",
"laser",
"monochrome",
"digital"
],
"vcd": [
12,
3,
6,
0
],
"dvd": [
1,
0,
0,
16
]
}
var arr_idx = [];
for (i = 0; i < records_object.record.length; i++) {
if (records_object.record[i].match(/digital/i) != null||
records_object.record[i].match(/analog/i) != null) {
arr_idx.push(i);
}
}
for (el in records_object) {
records_object[el] = records_object[el].filter(function (x, i) {
return arr_idx.indexOf(i) != -1;
});
}
console.log(records_object);
so far i was able to do this , now i am stuck
const getIndex = (data) => {
return data.record
.map((e, i) =>
e.includes("analog") || e.includes("digital") ? i : undefined
)
.filter((x) => x !== undefined);
};
You can do this,
var records_object = {
"record": [
"analog",
"laser",
"monochrome",
"digital"
],
"vcd": [
12,
3,
6,
0
],
"dvd": [
1,
0,
0,
16
]
}
let arrayIndexes = records_object.record.map((item, index) => {
if(item.match(/digital/i) != null || item.match(/analog/i) !== null) {
return index;
}
}).filter(item => item !== undefined);
let newObject = Object.keys(records_object).reduce((prev, key) => {
prev[key] = records_object[key].filter((item, index) => arrayIndexes.includes(index));
return prev;
}, {});
console.log(newObject);
The problem was with filter.
when you are running map it returns array [0, undefined, undefined, 3] and that array is being filtered and as you are using filter(x => x), this will iterate through the returned array and remove all the falsy values and return the resulting array.
In [0, undefined, undefined, 3]'s case, only 3 is the truthy value and that's why you are getting only [3] as 0 too is falsy.
You can modify your code slightly to get this resolved.
var records_object = {
record: ["analog", "laser", "monochrome", "digital"],
vcd: [12, 3, 6, 0],
dvd: [1, 0, 0, 16],
};
const getIndex = (data) => {
return data.record
.map((e, i) =>
e.includes("analog") || e.includes("digital") ? i : undefined
)
.filter((x) => x !== undefined);
};
console.log(getIndex(records_object));
Here is the solution using reduce and filter function. I've saved the result in new object.
var records_object = {
"record": [
"analog",
"laser",
"monochrome",
"digital"
],
"vcd": [
12,
3,
6,
0
],
"dvd": [
1,
0,
0,
16
]
};
const matchByString = ['analog', 'digital'];
const isMatch = (el, stringElements) => stringElements.some((strEl) => el.match(new RegExp(strEl, 'i')) != null);
const filterByIndex = records_object.record.reduce((acc, el, index) => isMatch(el, matchByString) ? [...acc, index] : acc, [])
const result = {};
Object.keys(records_object).forEach(i => result[i] = records_object[i].filter((el, i) => filterByIndex.includes(i)));
console.log(result)
I am having an object of objects where each object has a key and an array as a value. This is what I was having image. I had some arrays with values less than x elements (in this case it's 20) in each array so I wrote this code to pad my arrays with zeros. here is the output of my code image. However, as you can see, the code isnt working when having an array with null values only. This has put me off for a while.
here is my code:
let results[tab] = {
"Capital Cost ($)": [-2176346066.1517634],
"Electricity Revenue ($)":
[25128866.14469719, 34695653.93022109, 42581870.9302151, 48994313.58438795],
"Net Present Value ($)": [null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null]
}
const maxLength = Object.values(results[tab]).map( x => x.map( x=> x === null ? 0 : x))
.reduce( (acc, item) => Math.max(acc, item.length), 0);
const new_values = Object.values(results[tab]).map( value => value.concat(Array(maxLength - value.length).fill(0)));
const keys = Object.keys(results[tab]);
var toObj = (ks, vs) => ks.reduce((o,k,i)=> {o[k] = vs[i]; return o;}, {});
const new_results = toObj(keys, new_values);
console.log(new_results)
Solution: So It turned out that map doesnt apply the new condition. Solved!
type of x can never be null, as null is a value not a type. even the type of null is object. so there is no need of typeof in your code.
I have two arrays both are of variable length, I want to achieve a pattern, which I have already achieved but not satisfied with my solution. I believe there could be a better way to achieve the same.
const logic = (outerArray, innerArray) => outerArray.map((outerVal, OuterIndex) => {
return innerArray.map((innerVal, innerIndex) => {
const currentSlideIndex = OuterIndex + 1;
if (innerArray.length < 6 && innerIndex + 1 === currentSlideIndex) return true;
if (innerArray.length === 6) {
if (innerIndex < 4 && innerIndex + 1 === currentSlideIndex) return true;
// return false if currentslide is greater than four and less than last two slides
if (currentSlideIndex > 4 && currentSlideIndex < outerArray - 1 && innerIndex === 3) {
return true;
}
if (innerIndex === 4 && currentSlideIndex === outerArray - 1) return true;
if (innerIndex === 5 && currentSlideIndex === outerArray) return true;
}
return '';
});
});
Expected results
if innerArray length is less than or equal to 6 it should return array of length as innerArray and also the output should look like
logic([1,2,3,4,5],[1,2,3,4,5])
Expected output
[
[true, "", "", "", ""],
["", true, "", "", ""],
["", "", true, "", ""],
["", "", "", true, ""],
["", "", "", "", true]
]
if outerArray length is greater than 6 then it should work same for 3 index and should return true for index 4 for all outerArray index and resume at last two index.
logic([1,2,3,4,5,6,7,8,9,10],[1,2,3,4,5,6])
Expected output
[
[true,"","","","",""],
["",true,"","","",""],
["","",true,"","",""],
["","","",true,"",""],
["","","",true,"",""],
["","","",true,"",""],
["","","",true,"",""],
["","","",true,"",""],
["","","","",true,""],
["","","","","",true]
]
I would split your code into two functions. The first one would return the column index of each value of your outerArray like so:
const getColumnIndexes = (array) => {
// Get first 3 items
let columnIndexes = array.slice(0, 3);
// Get items in 4th column
columnIndexes = columnIndexes.concat(array.slice(3, Math.max(4, array.length - 2)).map(() => 4));
// Get last 2 items
columnIndexes = columnIndexes.concat(array.slice(Math.max(4, array.length - 2), array.length).map((val, index) => 5 + index));
return columnIndexes;
};
Then your logic function becomes really simple:
const logic = outerArray => {
const columnIndexes = getColumnIndexes(outerArray);
return outerArray.map((val, lineIndex) => {
return Array(Math.min(6, outerArray.length)).fill().map((_, i) => i === columnIndexes[lineIndex] - 1 ? true : "");
});
};
If I understood properly, you don't actually need this innerArray anymore.
logic([1, 2, 3, 4, 5]);
[
[true, "", "", "", ""],
["", true, "", "", ""],
["", "", true, "", ""],
["", "", "", true, ""],
["", "", "", "", true]
]
logic([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
[
[true,"","","","",""],
["",true,"","","",""],
["","",true,"","",""],
["","","",true,"",""],
["","","",true,"",""],
["","","",true,"",""],
["","","",true,"",""],
["","","",true,"",""],
["","","","",true,""],
["","","","","",true]
]
In the below function I am attempting to get an output which resembles this:
[[1,1,1,1],[2,2,2], 4,5,10,[20,20], 391, 392,591].
I can see that the problem I have embedded is that I am always adding the temp array with a push to the functions return, as a result, all of the individual numbers apart from the last number in the for each function are being pushed into the target array with the array object also.
I feel as though I need a further conditonal check but for the life of me I am unable to come up with solution which works.
Any suggestions would be much appreciated.
const sortme = (unsortedArr)=> {
let tempArr = [];
let outputArr = [];
const reorderedArr = unsortedArr.sort((a,b) => a-b);
reorderedArr.forEach((number, i) => {
if ((i === 0) || (reorderedArr[i] === reorderedArr[i-1])) {
tempArr.push(number);
}
else {
outputArr.push(tempArr);
tempArr = [];
tempArr.push(number);
}
})
outputArr.push(tempArr[0]);
return outputArr;
}
const unsortedArr = [1,2,4,591,392,391,2,5,10,2,1,1,1,20,20];
sortme(unsortedArr);
i would make a deduped copy and .map() it to transform the values into arrays containing values from the original ( sorted ) array that you get using a .forEach :
const unsortedArr = [1, 2, 4, 591, 392, 391, 2, 5, 10, 2, 1, 1, 1, 20, 20];
const sortMe = (arr) => {
arr = arr.sort((a, b) => a - b);
// a short way to dedupe an array
// results in : 1, 2, 4, 5, 10, 20, 391, 392, 591
let dedupe = [...new Set(arr)];
let tmpArr;
return dedupe.map(e => {
tmpArr = []; // empty tmpArr on each iteration
// for each element of the deduped array, look for matching elements in the original one and push them in the tmpArr
arr.forEach(a => {
if (a === e)
tmpArr.push(e);
})
if(tmpArr.length === 1)
return tmpArr[0]; // in case you have [4] , just return the 4
else
return tmpArr; // in case you have [1,1,1,1]
// shorthand for the if/else above
// return tmpArr.length === 1 ? tmpArr[0] : tmpArr;
});
}
const result = sortMe(unsortedArr);
console.log(result);
This should work (using reduce):
const unsortedArr = [1,2,4,591,392,391,2,5,10,2,1,1,1,20,20];
let lastValue = null;
var newArr = unsortedArr.sort((a,b) => a-b).reduce((acc, value) => {
if (acc.length == 0 || ((acc.length > 0 || !acc[acc.length-1].length) && lastValue !== value)) {
acc.push(value);
} else if (acc.length > 0 && lastValue === value) {
acc[acc.length-1] = (acc[acc.length-1].length ? acc[acc.length-1].concat([value]): [value, value]);
}
lastValue = value;
return acc;
}, []);
console.log(newArr);
And another approach, just for fun:
const unsortedArr = [1,2,4,591,392,391,2,5,10,2,1,1,1,20,20];
var arr = unsortedArr.sort((a,b) => a-b).reduce((acc, value) => {
if (acc.length > 0 && acc[acc.length-1].includes(value)) {
acc[acc.length-1].push(value);
} else {
acc.push([value])
}
return acc;
}, []).map((v) => v.length > 1 ? v: v[0]);
console.log(arr);
I hope the below one is quite simple;
function findSame(pos, sortedArr){
for(let i =pos; i<sortedArr.length; i++){
if(sortedArr[i] !== sortedArr[pos]){
return i
}
}
}
function clubSameNumbers(unsortedArr){
let sortedArr = unsortedArr.sort((a,b)=>a-b)
//[ 1, 1, 1, 1, 2, 2, 2, 4, 5, 10, 20, 20, 391, 392, 591 ]
let result = []
for(let i = 0; i < sortedArr.length; i = end){
let start = i
var end = findSame(i, sortedArr)
let arr = sortedArr.slice(i, end)
arr.length > 1 ? result.push(arr) : result.push(...arr)
}
return result
}
console.log(clubSameNumbers([1,2,4,591,392,391,2,5,10,2,1,1,1,20,20]))
//[ [ 1, 1, 1, 1 ], [ 2, 2, 2 ], 4, 5, 10, [ 20, 20 ], 391, 392, 591 ]
I have an array like this:
["name1", "name2", null, null, "name5", null]
I want to make it like this:
["name1 wow", "name2 wow", null, null, "name5 wow", null]
I tried to do it like this:
myCtrl.myArray.map(s => s + " wow");
Seems it's not the right solution, any ideas?
Try Aarry's map() with the help of ternary operator like the following:
var arr = ["name1", "name2", null, null, "name5", null];
var res = arr.map(function(item){
return item != null ? item + ' wow' : null;
});
console.log(res);
You could use a logical AND && for checking falsy values and return the falsy value direcly or concat the value with a postfix.
You need to assign the result array of Array#map to a new or the old variable.
var array = ["name1", "name2", null, null, "name5", null],
result = array.map(s => s && s + " wow");
console.log(result);
Do your adding stuff only if s is not null
myCtrl.myArray.map(s => (s==null?null:s + " wow"));
Add condition for null checking
let a = ["name1", "name2", null, null, "name5", null];
console.log(a.map(s => s == null ? null : (s + ' wow') ));
For the sake of completeness, you don't actually have to compare to null:
var arr = ["name1", "name2", null, null, "name5", null];
var res = arr.map(function(item) {
return item ? item + ' wow' : null;
});
console.log(res);