I am trying to only return 1's from this array but I am having trouble figuring out whats wrong with my code.
let arr = [[1],[1,2],[3],[1,2],[4],[1,2],[1]];
let ok = arr.filter((x) => {
if(x.length > 1){
return x.filter((y) => {
return y == 1;
})
}else{
return x == 1;
}
})
console.log(ok);
Your inner x.filter returns a new filtered array. But that is not really used as it is passed to the outer filter, which will then take that to decide wether to filter the outer one. So actually it seems as the outer filter should actually map:
let ok = arr.map(inner => inner.filter(el => el === 1));
You also do not need that if statement as the code works nevertheless.
Jonas gave a very good answer above, though I'm not sure this is what was asked. I have a feeling :) that you need only arrays which were exactly [1] in the original array arr. If so:
const arr = [[1],[1,2],[3],[1,2],[4],[1,2],[1]];
const ok = arr.filter(el => el.length === 1 && el[0] === 1) // [[1], [1]]
Related
I work on an Angular project and I built an array.
Now I'd like to rename one of the items of the array. I found the way to rename the keys of an array but I still don't know how to do to apply this to its values.
Here is my array below.
I'd like to change 'valueC' by 'valueZ'.
myArray = ['valueA', 'valueB', 'valueC']
I tried the following code :
for (const k in this.myArray) {
if (k == "valueC") {
this.myArray[k] = "valueZ";
}
But it does not work.
Could you help me ?
Any help would be very appreciated, thanks.
Below are two possible methods!
const myArray = ['valueA', 'valueB', 'valueC']
//rename - if index known
myArray[2] = 'valueZ';
console.log('if index known', myArray);
//rename - if index not known
const foundIndex = myArray.findIndex(x => x === 'valueC');
if (foundIndex > -1) {
myArray[2] = 'valueZ';
}
console.log('if index not known', myArray);
Your code just needs a minor correction:
if (this.myArray[k] == "valueC")
Try this:
const myArray = ['valueA', 'valueB', 'valueC'];
for (const k in myArray) {
if (myArray[k] == "valueC") {
myArray[k] = "valueZ";
}
}
console.log(myArray);
You need to track the index, easy with a forEach
this.myArray.forEach((k, index) => {
if (k == "valueC") {
this.myArray[index] = "valueZ";
}
})
My prefered way :
Though, be sure to have the value "valueC" inside the array
otherwise indexOf will return a -1, provoquing an error
// without index control
this.myArray[this.myArray.indexOf("valueC")] = "valueZ";
// with index control
const index = this.myArray.indexOf("valueC")
if (index >= 0) {
this.myArray[index] = "valueZ";
}
Also note this for future usage :)
for (const k in array) : in that case k is the index of elements in array
for (const k of array) : in that case k is the value of elements in array
On top of all the other solutions here, another approach, and one I believe is better in that it gets you in the mindset of immutability, is to return a new object instead of modifying the current one.
Ex:
this.myArray = this.myArray.map(x => {
if(x !== 'valueC')
return x;
return 'valueZ';
});
So map here will return a new array object for us, in this case a string array given your current array is a string array. Another pattern in use here is only checking for the negative case. Instead of having if/else or a chain of them, we know that for all case that aren't 'valueC' we retain their original value and only valueC's value needs to change to valueZ
I am coming from Python and I am looking for a single line iterator function for any array, where I can also check a condition and return a simple change to the items.
Expected result should match the method:
function arrayEvenItemIncrement(myArray){
for (let i = 0; i < myArray.length; i++){
if (myArray[i]%2==0){
myArray[i]++;
}
}
return myArray;
}
I tried using for (i of myArray){ } but this still doesn't serve my purpose.
I think the clearest way to do what you want here would be to map to a new array instead of mutating the old one:
const arrayEvenItemIncrement = myArray =>
myArray.map((val, i) => i % 2 === 1 ? val : val + 1);
If you have to mutate the existing array, it gets significantly uglier.
const arrayEvenItemIncrement = myArray => (
myArray.forEach((val, i) => { if (i % 2 === 0) myArray[i]++; }), myArray);
or
const arrayEvenItemIncrement = myArray => {
myArray.forEach((val, i) => { if (i % 2 === 0) myArray[i]++; }); return myArray };
But I wouldn't recommend that - put it on multiple lines instead.
You can technically squeeze any JS code into a single line, but past simple manipulations, it usually isn't a good idea because it sacrifices readability, which is far more important than reducing LoC. Professional, maintainable code is not a golfing competition.
Thank you for the answers.
I have settled for this:
myArray.forEach(el=>el%2===0?newArray.push(el):null);
I need to get an array as input and store the result to be used, without creating other functions because I have no access. So the code must be what result can get.
let array = [[1,2,3,4,5,10],[1,2,3,4,5,20]];
let result = array
.forEach(
function(el){
if(el[5] == 10)
{
return(el); //must store to variable, but this doesn't work
}
}
)
I know I'm missing the point but can't figure it out. How can I make this work?
Since you need only some especific elements, you need a make a filter on the array
let array = [[1,2,3,4,5,10],[1,2,3,4,5,20]];
let result = array.filter((el) => el[5] == 10)
Use filter().
let result = array.filter(el => el[5] === 10);
I have an Array and i would like to Filter or delete the following urls from my Array every time they appear:
"https://basueUrl.com/Claim"
"https://basueUrl.com/ExplanationOfBenefit"
My Array
Array= [
"https://basueUrl.com/Patient"
"https://basueUrl.com/Organization"
"https://basueUrl.com/Claim"
"https://basueUrl.com/Practitioner"
"https://basueUrl.com/Encounter"
"https://basueUrl.com/Condition"
"https://basueUrl.com/Claim"
"https://basueUrl.com/ExplanationOfBenefit"
"https://basueUrl.com/Claim"
"https://basueUrl.com/ExplanationOfBenefit"
"https://basueUrl.com/ExplanationOfBenefit"
]
First Solution I have tried for loop but did not work?
for( var i = 0; i < Array.length; i++){
if ( Array[i] === "https://basueUrl.com/ExplanationOfBenefit" & "https://basueUrl.com/Claim") {
Array.splice(i, 1);
i--;
}
}
console.log(Array);
Second Solution I tried making a remove method did not work either.
function arrayRemove(Array, value) {
return Array.filter(function(ele){
return ele != value;
});
}
var result = arrayRemove(Array,"https://basueUrl.com/ExplanationOfBenefit" & "https://basueUrl.com/Claim");
Any suggestion please?
The first approach is modifying the array while the loop is being executed, which generates problem with the index because the array.length changes when you call Array.prototype.splice.
In the second approach, you're not passing what you think
console.log("https://basueUrl.com/ExplanationOfBenefit" & "https://basueUrl.com/Claim");
// A number? probably you want an array.
You can use the function filter and the function includes as follow:
let skip = ["https://basueUrl.com/Claim", "https://basueUrl.com/ExplanationOfBenefit"];
let arr = ["https://basueUrl.com/Patient","https://basueUrl.com/Organization","https://basueUrl.com/Claim","https://basueUrl.com/Practitioner","https://basueUrl.com/Encounter","https://basueUrl.com/Condition","https://basueUrl.com/Claim","https://basueUrl.com/ExplanationOfBenefit","https://basueUrl.com/Claim","https://basueUrl.com/ExplanationOfBenefit","https://basueUrl.com/ExplanationOfBenefit"];
let result = arr.filter(url => !skip.includes(url));
console.log(result);
Array.filter(x => x !== "https://basueUrl.com/Claim" && x !== "https://basueUrl.com/ExplanationOfBenefit")
var Array= [
"https://basueUrl.com/Patient",
"https://basueUrl.com/Organization",
"https://basueUrl.com/Claim",
"https://basueUrl.com/Practitioner",
"https://basueUrl.com/Encounter",
"https://basueUrl.com/Condition",
"https://basueUrl.com/Claim",
"https://basueUrl.com/ExplanationOfBenefit",
"https://basueUrl.com/Claim",
"https://basueUrl.com/ExplanationOfBenefit",
"https://basueUrl.com/ExplanationOfBenefit"
];
var filteredArray = Array.filter(item => item !== "https://basueUrl.com/Claim" && item !== "https://basueUrl.com/ExplanationOfBenefit")
console.log(filteredArray)
You can run the code below. Hope this helps.
// use this array instead on the original. It creates a new array from the original
// array.
const newFilteredArray = Array.filter(url => url !== 'https://basueUrl.com/Claim' &&
url !== 'https://basueUrl.com/ExplanationOfBenefit');
Please see below the way you can achieve the above mentioned scenario.
arr.filter(ele=>ele!=="https://basueUrl.com/Claim"
&& ele!=="https://basueUrl.com/ExplanationOfBenefit");
My main goal for academic purposes is to solve this problem and for the most part I did. Also I wanted to make sure that I was not missing a fundamental part of reduce by not understanding what is wrong with my code.
This is how I would solve it, I've attached my reduce function as well as filter function. I believe my reduce function works however, my filter function isn't quite working so well as I can't pass my test cases.
1) Why am i not hitting the last element of the array?
I've noticed that prev and curr actually never return 5 at any point of the reduce function. Am I missing something in my reduce function?
myArray = [1,2,3,4,5];
function each(collection, action){
if(Array.isArray(collection)){
for(var i = 0; i < collection.length; i ++){
action(collection[i]);
}
}
else if(typeof(collection) === "object"){
for (var property in collection){
action(collection[property]);
}
}
}
function reduce(collection, combine, start){
each(collection, function(element){
if(start === undefined){
return start = element;
}
else {
return start = combine(start, element);
}
});
return start;
}
function filterR(collection, predicate){
var aR = [];
reduce(collection, function(prev, curr){
if(predicate(prev)){
aR.push(prev);
}
if(predicate(curr)){
aR.push(curr);
}
});
return aR;
}
console.log(filter(myArray, function(val){return val % 5 === 0;})); //expected [5]
console.log(filter(myArray, function(val){return val <= 5;})); //expected [1,2,3,4,5]
I can't diagnose your problem because I don't know what your each procedure is.
Anyway, it doesn't matter; you're overthinking it.
reduce is very simple to implement by hand.
function reduce(f, start, arr) {
if (arr.length === 0)
return start;
else
return reduce(f, f(start, arr[0]), arr.slice(1));
}
// example
function add(x,y) { return x+y; }
reduce(add, 0, []); //=> 0
reduce(add, 0, [1,2,3]); //=> 6
I see that you are trying to support a sort of reduce without an optional starting value. That is impossible if your reduce function is to be considered a total function. A starting value is required. Don't try to be clever.
Now a filter implemented using reduce
function filter(f, arr) {
return reduce(function(result, x) {
if (f(x))
return result.concat([x]);
else
return result;
}, [], arr);
}
Your examples
var myArray = [1,2,3,4,5];
filter(function(val){return val % 5 === 0;}, myArray)
//=> [5]
filter(function(val){return val <= 5;}, myArray)
//=> [1, 2, 3, 4, 5]
If you want to learn more...
There are other ways to implement reduce as well. One such improvement you could make is to put the recursion in tail position. When JavaScript engines support tail call elimination (with ES6), this would prevent reduce from stack-overflowing for significantly large values of arr.
function reduce(f, start, arr) {
function loop(result, arr) {
if (arr.length === 0)
return result;
else
return loop(f(result, arr[0]), arr.slice(1));
}
return loop(start, arr);
}
A blackhole appears...
With reduce and higher-order functions under your belt, you now stand at the shores of the deep, vast sea that is lambda calculus and functional programming. If you're feeling very zealous, you can explore how currying and combinators change this definition even more dramatically.
The following code is written in ES6
// U-combinator
const U = f=> f(f);
// Y-combinator
const Y = U (h=> f=> f (x=> h (h) (f) (x)));
// reduce
const reduce = f=> Y(h=> start=> arr=>
arr.length === 0
? start
: h (f (start) (arr[0])) (arr.slice(1)));
// filter
const filter = f=>
reduce(result=> x=>
f(x) ? result.concat([x]) : result) ([]);
// your examples again...
var myArray = [1,2,3,4,5];
filter (x=> x % 5 === 0) (myArray) //=> [5]
filter (x=> x <= 5) (myArray) //=> [1, 2, 3, 4, 5]
Why am i not hitting the last element of the array?
I don't know. It might be an error in your each-function, wich is not posted here. But since you have some more flaws in boh of your functions, I'll add a working implementation.
I've noticed that prev and curr actually never return 5 at any point of the reduce function.
prev and curr never return anything, they are arguments. And that particular function itself, also doesn't ever return anything.
First start === undefined is no proper check to determine wether yo want to initialize the result-value with the first(current)-element. undefined is an unexpected, even unwanted value in that place, but it is actually perfectly fine. So with that check, your reduce-function might start over again, in the middle of the collection.
Just take a look at the previously mentioned function you utilize in filter. This function does return undefined (as the value for the next iteration) ;) so that prev will always be undefined in your code.
Then, reduce makes no sense in your filter-function, at least the way you use it. You use it as each.
function reduce(collection, combine, start){
var result = start, hasValue = arguments.length > 2;
each(collection, function(element){
if(hasValue){
result = combine(result, element);
}else{
result = element;
hasValue = true;
}
});
if(!hasValue){
//no start/default-value, no elements in the collection,
//what result do you expect from this reduce-task?
throw new Error("reduce of empty array with no initial value");
}
return result;
}
function filter(collection, predicate){
return reduce(collection, function(result, elm){
//the functional-approach: no mutations
return predicate(elm)?
result.concat( [elm] ):
result;
//or a more sane way to do this in JS
if( predicate(elm) ) result.push( elm );
return result;
}, []);
}