Ism*_*ail 336 javascript
如何跳过数组元素.map?
我的代码:
var sources = images.map(function (img) {
if(img.src.split('.').pop() === "json"){ // if extension is .json
return null; // skip
}
else{
return img.src;
}
});
Run Code Online (Sandbox Code Playgroud)
这将返回:
["img.png", null, "img.png"]
Run Code Online (Sandbox Code Playgroud)
Poi*_*nty 516
就是.filter()第一个:
var sources = images.filter(function(img) {
if (img.src.split('.').pop() === "json") {
return false; // skip
}
return true;
}).map(function(img) { return img.src; });
Run Code Online (Sandbox Code Playgroud)
如果你不想这样做,这是不合理的,因为它有一些成本,你可以使用更一般.reduce().你一般可以表现.map()在以下方面.reduce:
someArray.map(function(element) {
return transform(element);
});
Run Code Online (Sandbox Code Playgroud)
可写成
someArray.reduce(function(result, element) {
result.push(transform(element));
return result;
}, []);
Run Code Online (Sandbox Code Playgroud)
因此,如果您需要跳过元素,可以通过以下方式轻松完成.reduce():
var sources = images.reduce(function(result, img) {
if (img.src.split('.').pop() !== "json") {
result.push(img.src);
}
return result;
}, []);
Run Code Online (Sandbox Code Playgroud)
在该版本中,.filter()第一个示例中的代码是.reduce()回调的一部分.在过滤器操作保留它的情况下,仅将图像源推送到结果数组上.
the*_*trk 19
更新:我认为我对此答案所知的一切都是错误的
我们不应该要求增加点链和操作数组,[].map(fn1).filter(f2)...因为这种方法在每个reducing函数的内存中创建中间数组.
最好的方法是对实际的减少函数进行操作,因此只有一次数据传递而没有额外的数组.
reduce函数是传入函数reduce并从源获取累加器和输入并返回看起来像累加器的东西
// 1. create a concat reducing function that can be passed into `reduce`
const concat = (acc, input) => acc.concat([input])
// note that [1,2,3].reduce(concat, []) would return [1,2,3]
// transforming your reducing function by mapping
// 2. create a generic mapping function that can take a reducing function and return another reducing function
const mapping = (changeInput) => (reducing) => (acc, input) => reducing(acc, changeInput(input))
// 3. create your map function that operates on an input
const getSrc = (x) => x.src
const mappingSrc = mapping(getSrc)
// 4. now we can use our `mapSrc` function to transform our original function `concat` to get another reducing function
const inputSources = [{src:'one.html'}, {src:'two.txt'}, {src:'three.json'}]
inputSources.reduce(mappingSrc(concat), [])
// -> ['one.html', 'two.txt', 'three.json']
// remember this is really essentially just
// inputSources.reduce((acc, x) => acc.concat([x.src]), [])
// transforming your reducing function by filtering
// 5. create a generic filtering function that can take a reducing function and return another reducing function
const filtering = (predicate) => (reducing) => (acc, input) => (predicate(input) ? reducing(acc, input): acc)
// 6. create your filter function that operate on an input
const filterJsonAndLoad = (img) => {
console.log(img)
if(img.src.split('.').pop() === 'json') {
// game.loadSprite(...);
return false;
} else {
return true;
}
}
const filteringJson = filtering(filterJsonAndLoad)
// 7. notice the type of input and output of these functions
// concat is a reducing function,
// mapSrc transforms and returns a reducing function
// filterJsonAndLoad transforms and returns a reducing function
// these functions that transform reducing functions are "transducers", termed by Rich Hickey
// source: http://clojure.com/blog/2012/05/15/anatomy-of-reducer.html
// we can pass this all into reduce! and without any intermediate arrays
const sources = inputSources.reduce(filteringJson(mappingSrc(concat)), []);
// [ 'one.html', 'two.txt' ]
// ==================================
// 8. BONUS: compose all the functions
// You can decide to create a composing function which takes an infinite number of transducers to
// operate on your reducing function to compose a computed accumulator without ever creating that
// intermediate array
const composeAll = (...args) => (x) => {
const fns = args
var i = fns.length
while (i--) {
x = fns[i].call(this, x);
}
return x
}
const doABunchOfStuff = composeAll(
filtering((x) => x.src.split('.').pop() !== 'json'),
mapping((x) => x.src),
mapping((x) => x.toUpperCase()),
mapping((x) => x + '!!!')
)
const sources2 = inputSources.reduce(doABunchOfStuff(concat), [])
// ['ONE.HTML!!!', 'TWO.TXT!!!']
Run Code Online (Sandbox Code Playgroud)
mpe*_*pen 15
这是一个有趣的解决方案:
/**
* Filter-map. Like map, but skips undefined values.
*
* @param callback
*/
function fmap(callback) {
return this.reduce((accum, ...args) => {
let x = callback(...args);
if(x !== undefined) {
accum.push(x);
}
return accum;
}, []);
}
Run Code Online (Sandbox Code Playgroud)
[1,2,-1,3]::fmap(x => x > 0 ? x * 2 : undefined); // [2,4,6]
Run Code Online (Sandbox Code Playgroud)
sim*_*eco 14
我认为从数组跳过一些元素的最简单方法是使用filter()方法.
通过使用此方法和ES6语法,您可以在一行中编写代码:
let sources = images.filter(img => img.src.slice(-4) != 'json').map(img => img.src);
Run Code Online (Sandbox Code Playgroud)
这将返回你想要的东西:
let images = [{src: 'img.png'}, {src: 'j1.json'}, {src: 'img.png'}, {src: 'j2.json'}];
let sources = images.filter(img => img.src.slice(-4) != 'json').map(img => img.src);
console.log(sources);Run Code Online (Sandbox Code Playgroud)
cor*_*ons 11
没有多余的边缘案例:
const thingsWithoutNulls = things.reduce((acc, thing) => {
if (thing !== null) {
acc.push(thing);
}
return acc;
}, [])
Run Code Online (Sandbox Code Playgroud)
Luc*_* P. 11
var sources = images.map(function (img) {
if(img.src.split('.').pop() === "json"){ // if extension is .json
return null; // skip
}
else{
return img.src;
}
}).filter(Boolean);
Run Code Online (Sandbox Code Playgroud)
的.filter(Boolean)将在给定阵列中,而你的情况是中滤除任何falsey值null。
为什么不只使用forEach循环?
let arr = ['a', 'b', 'c', 'd', 'e'];
let filtered = [];
arr.forEach(x => {
if (!x.includes('b')) filtered.push(x);
});
console.log(filtered) // filtered === ['a','c','d','e'];Run Code Online (Sandbox Code Playgroud)
或更简单的使用过滤器:
const arr = ['a', 'b', 'c', 'd', 'e'];
const filtered = arr.filter(x => !x.includes('b')); // ['a','c','d','e'];
Run Code Online (Sandbox Code Playgroud)
要推断Felix Kling 的评论,您可以这样使用.filter():
var sources = images.map(function (img) {
if(img.src.split('.').pop() === "json") { // if extension is .json
return null; // skip
} else {
return img.src;
}
}).filter(Boolean);
Run Code Online (Sandbox Code Playgroud)
这将从返回的数组中删除 falsey 值 .map()
您可以像这样进一步简化它:
var sources = images.map(function (img) {
if(img.src.split('.').pop() !== "json") { // if extension is .json
return img.src;
}
}).filter(Boolean);
Run Code Online (Sandbox Code Playgroud)
或者甚至作为使用箭头函数、对象解构和&&运算符的单行:
var sources = images.map(({ src }) => src.split('.').pop() !== "json" && src).filter(Boolean);
Run Code Online (Sandbox Code Playgroud)
Array.prototype.flatMap是另一个选项。
images.flatMap(({src}) => src.endsWith('.json') && [] || src);
Run Code Online (Sandbox Code Playgroud)
从MDN:
flatMap可以用作在地图中添加和删除项目(修改项目数)的方法。换句话说,它允许您将许多项目映射到许多项目(通过分别处理每个输入项目),而不是始终一对一。从这个意义上讲,它的作用类似于过滤器。只需返回一个1元素数组以保留该项目,返回一个多元素数组以添加项目,或返回0元素数组以删除该项目。