如何跳过.map()中的元素?

跳过.map中元素的高级方法
本文探讨了在JavaScript中跳过数组.map方法中特定元素的多种技巧,包括使用.filter()、.reduce()和.transducers概念。通过示例代码展示了如何避免创建不必要的中间数组,提高性能。
部署运行你感兴趣的模型镜像

本文翻译自:How to skip over an element in .map()?

How can I skip an array element in .map ? 如何跳过.map的数组元素?

My code: 我的代码:

var sources = images.map(function (img) {
    if(img.src.split('.').pop() === "json"){ // if extension is .json
        return null; // skip
    }
    else{
        return img.src;
    }
});

This will return: 这将返回:

["img.png", null, "img.png"]

#1楼

参考:https://stackoom.com/question/1g5NE/如何跳过-map-中的元素


#2楼

Just .filter() it first: 只是.filter()首先:

var sources = images.filter(function(img) {
  if (img.src.split('.').pop() === "json") {
    return false; // skip
  }
  return true;
}).map(function(img) { return img.src; });

If you don't want to do that, which is not unreasonable since it has some cost, you can use the more general .reduce() . 如果您不想这样做,因为这样做要花一些钱,这并不是不合理的,则可以使用更通用的.reduce() You can generally express .map() in terms of .reduce : 你通常可以表达.map()中的条款.reduce

someArray.map(function(element) {
  return transform(element);
});

can be written as 可以写成

someArray.reduce(function(result, element) {
  result.push(transform(element));
  return result;
}, []);

So if you need to skip elements, you can do that easily with .reduce() : 因此,如果您需要跳过元素,则可以使用.reduce()轻松实现:

var sources = images.reduce(function(result, img) {
  if (img.src.split('.').pop() !== "json") {
    result.push(img.src);
  }
  return result;
}, []);

In that version, the code in the .filter() from the first sample is part of the .reduce() callback. 在该版本中,第一个示例的.filter()的代码是.filter() .reduce()回调的一部分。 The image source is only pushed onto the result array in the case where the filter operation would have kept it. 仅在过滤操作可以保留结果的情况下,才将图像源推入结果数组。


#3楼

TLDR: You can first filter your array and then perform your map but this would require two passes on the array (filter returns an array to map). TLDR:您可以先过滤数组,然后执行地图,但这需要对数组进行两次遍历 (过滤器将数组返回到地图)。 Since this array is small, it is a very small performance cost. 由于此阵列很小,因此性能成本非常低。 However if you want to imagine how this can be done with a single pass over the array, you can use an idea called "transducers" made popular by Rich Hickey. 但是,如果您想想象一下如何通过一次遍历数组就可以完成此操作,则可以使用Rich Hickey流行的一种名为“换能器”的想法。

Answer: 回答:

We should not require increasing dot chaining and operating on the array [].map(fn1).filter(f2)... since this approach creates intermediate arrays in memory on every reducing function. 我们不应该需要增加点链接和所述阵列上操作的[].map(fn1).filter(f2)...因为这种方法在存储器上的每个创建中间阵列reducing功能。

The best approach operates on the actual reducing function so there is only one pass of data and no extra arrays. 最好的方法是对实际的约简函数进行操作,因此只有一轮数据,没有额外的数组。

The reducing function is the function passed into reduce and takes an accumulator and input from the source and returns something that looks like the accumulator 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!!!']

Resources: rich hickey transducers post 资源: Rich Hickey传感器发布


#4楼

Here's a fun solution: 这是一个有趣的解决方案:

/**
 * 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;
    }, []);
}

Use with the bind operator : bind运算符一起使用

[1,2,-1,3]::fmap(x => x > 0 ? x * 2 : undefined); // [2,4,6]

#5楼

Here's a utility method (ES5 compatible) which only maps non null values (hides the call to reduce): 这是一个实用程序方法(与ES5兼容),它仅映射非null值(隐藏了reduce的调用):

 function mapNonNull(arr, cb) { return arr.reduce(function (accumulator, value, index, arr) { var result = cb.call(null, value, index, arr); if (result != null) { accumulator.push(result); } return accumulator; }, []); } var result = mapNonNull(["a", "b", "c"], function (value) { return value === "b" ? null : value; // exclude "b" }); console.log(result); // ["a", "c"] 


#6楼

Answer sans superfluous edge cases: 回答无用的边缘情况:

const thingsWithoutNulls = things.reduce((acc, thing) => {
  if (thing !== null) {
    acc.push(thing);
  }
  return acc;
}, [])

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

<think>我们需要分析给定的Kotlin代码片段,并将其转换为ArkTS类型系统下的等效类型。 原Kotlin代码: resolver.listAllGroups() ?.toGroupList() ?.filter { group -> group.contacts.isNotEmpty() } ?.map { it.toMap() } ?: emptyList() 步骤解析: 1. resolver.listAllGroups(): 可能返回一个可为null的对象(假设为GroupResolver类型) 2. ?.toGroupList(): 安全调用,将GroupResolver转换为一个Group列表(List<Group>?),如果上一步为null则跳过,返回null 3. ?.filter { ... }: 对上一步得到的List<Group>?进行过滤,过滤条件是group.contacts不为空(非空列表)。注意:filter返回新的List<Group>? 4. ?.map { ... }: 将过滤后的每个Group对象通过toMap()转换成另一个对象(假设为Map类型),返回List<Map>? 5. ?: emptyList(): 如果前面任意一步出现null(即整个链式调用结果为null),则使用空列表(emptyList())替代。 因此,整个表达式返回的类型是:List<Map>(非空,因为最后有?: emptyList()保证) 在ArkTS中,由于类型系统的差异,我们需要明确每一步的类型。假设我们有以下类型定义: 类型定义: GroupResolver: 包含方法listAllGroups(): GroupResolverResult | null GroupResolverResult: 包含方法toGroupList(): Array<Group> | null Group: 包含contacts: Array<Contact>,以及toMap(): Object 方法(这里我们用Record<string, any>表示一个普通对象) 那么,在ArkTS中,我们可以这样写: let groups: Array<Group> | null = resolver.listAllGroups()?.toGroupList(); let filtered: Array<Group> | null = groups?.filter(group => group.contacts.length > 0); let result: Array<Record<string, any>> = filtered?.map(group => group.toMap()) ?? []; 但是,我们也可以使用连续的链式调用,但是要注意ArkTS不支持安全调用链(?.)的连续操作符(目前ArkTS的安全调用运算符只能用于单层,不能连续多层,因此我们需要拆解)。 不过,实际上ArkTS支持可选链(Optional Chaining)和空值合并运算符(Nullish Coalescing)。我们可以这样写: resolver.listAllGroups()?.toGroupList()?.filter(group => group.contacts.length > 0)?.map(group => group.toMap()) ?? [] 但是,由于ArkTS的类型系统是强类型的,我们需要知道每一步可能返回的类型。 整个表达式的类型推导: 1. resolver.listAllGroups() 返回类型为 T1 | null (假设T1是toGroupList方法所属的类型) 2. T1?.toGroupList() 返回 Array<Group> | null 3. Array<Group> | null 调用?.filter,返回 Array<Group> | null (因为如果数组为null,则跳过filter返回null;如果非null,则返回一个新的非null数组?注意:filter不会将非null数组变成null,但这里的可选链操作使得输入为null时输出为null,输入非null时输出非null数组) 4. 然后调用?.map,同样返回 Array<Record<string, any>> | null 5. 最后用??,如果前面是null,则返回空数组(Array<Record<string, any>>),否则返回非null的Array<Record<string, any>>。 所以最终返回类型是:Array<Record<string, any>>(非空数组,可能为空数组,但不会是null) 因此,在ArkTS中,我们可以这样写: const result: Array<Record<string, any>> = resolver.listAllGroups()?.toGroupList()?.filter((group: Group) => group.contacts.length > 0)?.map((group: Group) => group.toMap()) ?? []; 注意:由于可选链的存在,每一步都有可能返回null,但是最后我们用??运算符确保最终结果是一个数组(可能为空数组)。 另外,在ArkTS中,数组用Array<T>表示,空数组就是[]。 所以,最后返回的是 Array<Record<string, any>> 类型的数据。 但是,我们也可以使用更具体的类型,比如: interface GroupMap { // 定义toMap()返回的对象结构 id: string; name: string; // ...其他字段 } 然后使用 Array<GroupMap> 作为类型。 因此,具体返回类型取决于toMap()方法的返回类型。但根据问题描述,我们不知道toMap()的具体结构,所以使用Record<string, any>表示一个普通对象。 结论:返回类型是一个非空的数组,数组元素是普通对象(键值对),即:Array<Record<string, any>>。 示例代码: // 假设类型定义 class Group { contacts: Array<Contact> = []; toMap(): Record<string, any> { return { id: 'someId', name: 'groupName', // ...其他属性 }; } } // 使用 const finalResult: Array<Record<string, any>> = resolver.listAllGroups()?.toGroupList()?.filter((group: Group) => group.contacts.length > 0)?.map((group: Group) => group.toMap()) ?? []; // finalResult 一定是数组(可能为空),不会是null 注意:在ArkTS中,可选链操作符(?.)和空值合并运算符(??)的行为与Kotlin类似。 因此,最终返回的数据类型是:`Array<Record<string, any>>`(一个元素为普通对象的数组) </think>在 ArkTS 中分析 `resolver.listAllGroups()?.toGroupList()?.filter { ... }?.map { ... } ?: emptyList()` 的返回值类型: ### 类型推导分析(基于 Kotlin 语法) ```kotlin // 原始 Kotlin 表达式 val result = resolver.listAllGroups() // 1. 返回 GroupResolver? 类型* ?.toGroupList() // 2. 返回 List<Group>? 类型 ?.filter { group -> // 3. 返回 List<Group>? 类型 group.contacts.isNotEmpty() } ?.map { it.toMap() } // 4. 返回 List<Map<K,V>>? 类型 ?: emptyList() // 5. 返回 List<Map<K,V>> 类型(非空) ``` ### 最终返回类型 **`List<Map<K, V>>`**(非空列表,但可能为空列表) - ✅ **非空性**:`?: emptyList()` 确保永远不会返回 `null` - ✅ **元素类型**:经过 `map { it.toMap() }` 转换后,每个元素都是 `Map` 类型 - ⚠️ **可能为空**:当初始查询无结果或所有组都被过滤时,返回 `emptyList()` ### ArkTS 等效实现 ```typescript // 类型定义 interface Group { contacts: Contact[]; toMap(): Record<string, any>; // 返回键值对对象 } // 实现表达式 const result: Array<Record<string, any>> = resolver.listAllGroups() // 1. GroupResolver | null ?.toGroupList() // 2. Array<Group> | undefined ?.filter(group => group.contacts.length > 0) // 3. Array<Group> | undefined ?.map(group => group.toMap()) // 4. Array<Record<string, any>> | undefined ?? []; // 5. Array<Record<string, any>> (非空) ``` ### 关键类型说明 | 步骤 | Kotlin 类型 | ArkTS 等效类型 | |------|-------------|----------------| | 初始值 | `GroupResolver?` | `GroupResolver \| null` | | `toGroupList()` 后 | `List<Group>?` | `Array<Group> \| undefined` | | `filter` 后 | `List<Group>?` | `Array<Group> \| undefined` | | `map` 后 | `List<Map<K,V>>?` | `Array<Record<string, any>> \| undefined` | | **最终结果** | `List<Map<K,V>>` | `Array<Record<string, any>>` | ### 空安全处理机制 1. **可选链操作符 `?.`** ```typescript // 任意步骤为 null/undefined 时中断执行 a?.b?.c?.d ``` 2. **空值合并运算符 `??`** ```typescript // 左侧为 null/undefined 时返回右侧默认值 possibleNullValue ?? defaultValue ``` 3. **最终保障**:`?? []` 确保始终返回有效数组(即使为空)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值