linqjs - linq to javascript
- 1. 遍历与展开#
- traverseBreadthFirst(广度优先遍历树结构)#
- traverseDepthFirst(深度优先遍历树结构)#
- flatten(展开嵌套序列)#
- selectMany(展开并映射,类似 flatMap)#
- scan(累积遍历,类似 reduce 但返回中间结果)#
- asEnumerable(转换为可枚举对象)#
- 2. 过滤与筛选#
- where(条件过滤)v#
- ofType(按类型筛选)#
- distinct(去重)#
- distinctUntilChanged(去重连续重复值)#
- except(排除指定集合元素)#
- takeWhile(取满足条件的连续元素)#
- skipWhile(跳过满足条件的连续元素)#
- takeExceptLast(排除最后一个元素)#
- isEmpty(判断序列是否为空)#
- 3. 转换与映射#
- select(映射元素)#
- choose(条件映射并过滤空值)#
- cast(强制类型转换)#
- pairwise(将相邻元素配对)#
- zip(合并两个序列为元组)#
- merge(合并多个序列)#
- alternate(交替插入元素)#
- insert(在指定位置插入元素)#
- reverse(反转序列)#
- shuffle(随机打乱顺序)#
- groupBy(按键分组)#
- partitionBy(按条件分区)#
- 4. 聚合与计算#
- aggregate(自定义累积计算)#
- sum(求和)#
- average(求平均值)#
- count(计数)#
- max / min(最大值/最小值)#
- maxBy/minBy`(按属性取最大/最小对象)#
- all(是否全部满足条件)#
- any(是否存在满足条件的元素)#
- weightedSample(按权重随机抽样)#
- 5. 序列操作与组合#
- concat(连接两个序列)#
- intersect(取交集)#
- union(取并集并去重)#
- sequenceEqual(判断序列相等)#
- buffer(分批次缓存元素)#
- skip(跳过前 N 个元素)#
- take(取前 N 个元素)#
- takeFromLast(取最后 N 个元素)#
- elementAt / elementAtOrDefault(按索引取元素)#
- first / firstOrDefault(取首个元素)#
- last / lastOrDefault(取末尾元素)#
- single / singleOrDefault(取唯一元素)#
- 6. 查找与索引#
- 7. 排序与分组#
- 8. 结果转换与输出#
- toArray(转换为数组)#
- toObject(转换为对象)#
- toDictionary(转换为字典)#
- toJSONString(转换为 JSON 字符串)#
- toJoinedString(连接为字符串)#
- write / writeLine(输出到控制台或流)#
- 9. 副作用与调试#
- doAction(执行副作用操作)#
- forEach(遍历执行操作)#
- trace(跟踪元素并输出日志)#
- log(记录日志)#
- catchError(捕获异常)#
- finallyAction(最终执行操作)#
- 10. 延迟执行与缓存#
- 11. 杂项与底层操作#
- 关键区别说明#
这里给大家推荐个js实现的linq,项目地址:mihaifm/linq
1. 遍历与展开#
traverseBreadthFirst
(广度优先遍历树结构)#
const tree = {
value: 1,
children: [
{ value: 2, children: [{ value: 4 }] },
{ value: 3 }
]
};
from(tree)
.traverseBreadthFirst(node => node.children)
.select(node => node.value)
.toArray(); // [1, 2, 3, 4]
traverseDepthFirst
(深度优先遍历树结构)#
from(tree)
.traverseDepthFirst(node => node.children)
.select(node => node.value)
.toArray(); // [1, 2, 4, 3]
flatten
(展开嵌套序列)#
from([1, [2, [3]], 4])
.flatten()
.toArray(); // [1, 2, 3, 4]
✔selectMany
(展开并映射,类似 flatMap
)#
from([{ items: [1, 2] }, { items: [3] }])
.selectMany(x => x.items)
.toArray(); // [1, 2, 3]
✔scan
(累积遍历,类似 reduce
但返回中间结果)#
from([1, 2, 3])
.scan((acc, x) => acc + x, 0)
.toArray(); // [1, 3, 6](每一步的累加结果)
asEnumerable
(转换为可枚举对象)#
const lazySeq = from([1, 2, 3]).asEnumerable();
lazySeq.where(x => x > 1).toArray(); // [2, 3]
2. 过滤与筛选#
✔where
(条件过滤)v#
from([1, 2, 3, 4])
.where(x => x % 2 === 0)
.toArray(); // [2, 4]
ofType
(按类型筛选)#
from([1, "a", 2, "b"])
.ofType("string")
.toArray(); // ["a", "b"]
✔distinct
(去重)#
from([1, 2, 2, 3])
.distinct()
.toArray(); // [1, 2, 3]
distinctUntilChanged
(去重连续重复值)#
from([1, 1, 2, 2, 1])
.distinctUntilChanged()
.toArray(); // [1, 2, 1]
✔except
(排除指定集合元素)#
from([1, 2, 3, 4])
.except([2, 4])
.toArray(); // [1, 3]
takeWhile
(取满足条件的连续元素)#
from([1, 2, 3, 2, 4])
.takeWhile(x => x < 3)
.toArray(); // [1, 2]
skipWhile
(跳过满足条件的连续元素)#
from([1, 2, 3, 2, 4])
.skipWhile(x => x < 3)
.toArray(); // [3, 2, 4]
✔takeExceptLast
(排除最后一个元素)#
from([1, 2, 3])
.takeExceptLast()
.toArray(); // [1, 2]
✔isEmpty
(判断序列是否为空)#
from([]).isEmpty(); // true
from([1]).isEmpty(); // false
3. 转换与映射#
✔select
(映射元素)#
from([1, 2])
.select(x => x * 2)
.toArray(); // [2, 4]
✔choose
(条件映射并过滤空值)#
from([1, 2, 3])
.choose(x => x % 2 === 0 ? x * 2 : null)
.toArray(); // [4]
-
- 如果
x
能被2整除(即x % 2 === 0
),则返回x * 2
。例如,2能被2整除,所以返回2 * 2 = 4
。 - 如果
x
不能被2整除,则返回null
。例如,1和3都不能被2整除,所以返回null
。
- 如果
cast
(强制类型转换)#
from(["1", "2"])
.cast(Number)
.toArray(); // [1, 2]
pairwise
(将相邻元素配对)#
from([1, 2, 3])
.pairwise()
.toArray(); // [[1, 2], [2, 3]]
zip
(合并两个序列为元组)#
from([1, 2])
.zip(["a", "b"], (a, b) => a + b)
.toArray(); // ["1a", "2b"]
✔merge
(合并多个序列)#
from([1, 2]).merge([3, 4]).toArray(); // [1, 2, 3, 4]
alternate
(交替插入元素)#
from([1, 3])
.alternate(2, 4)
.toArray(); // [1, 2, 3, 4]
✔insert
(在指定位置插入元素)#
from([1, 3])
.insert(1, 2)
.toArray(); // [1, 2, 3]
✔reverse
(反转序列)#
from([1, 2, 3]).reverse().toArray(); // [3, 2, 1]
shuffle
(随机打乱顺序)#
from([1, 2, 3]).shuffle().toArray(); // 随机排列,如 [2, 3, 1]
✔groupBy
(按键分组)#
from([{ id: 1, type: "A" }, { id: 2, type: "A" }, { id: 3, type: "B" }])
.groupBy(x => x.type)
.select(g => ({ type: g.key, count: g.count() }))
.toArray(); // [{ type: "A", count: 2 }, { type: "B", count: 1 }]
✔partitionBy
(按条件分区)#
from([1, 2, 3, 2, 4])
.partitionBy(x => x % 2 === 0)
.toArray(); // [[2, 2, 4], [1, 3]]
4. 聚合与计算#
✔aggregate
(自定义累积计算)#
from([1, 2, 3])
.aggregate((acc, x) => acc + x, 0); // 6
✔sum
(求和)#
from([10, 20]).sum(); // 30
average
(求平均值)#
from([10, 20]).average(); // 15
✔count
(计数)#
from([1, 2, 3]).count(); // 3
✔max
/ min
(最大值/最小值)#
from([5, 1, 3]).max(); // 5
from([5, 1, 3]).min(); // 1
✔maxBy/
minBy`(按属性取最大/最小对象)#
from([{ age: 20 }, { age: 30 }])
.maxBy(x => x.age); // { age: 30 }
from([{ name: "Bob", score: 80 }, { name: "Alice", score: 90 }])
.minBy(x => x.score); // { name: "Bob", score: 80 }
✔all
(是否全部满足条件)#
from([2, 4, 6]).all(x => x % 2 === 0); // true
✔any
(是否存在满足条件的元素)#
from([1, 3, 5]).any(x => x % 2 === 0); // false
weightedSample
(按权重随机抽样)#
from([{ value: "A", weight: 1 }, { value: "B", weight: 3 }])
.weightedSample(x => x.weight)
.take(1); // "B" 出现的概率是 75%
5. 序列操作与组合#
✔concat
(连接两个序列)#
from([1, 2]).concat([3, 4]).toArray(); // [1, 2, 3, 4]
✔intersect
(取交集)#
from([1, 2, 3]).intersect([2, 3, 4]).toArray(); // [2, 3]
✔union
(取并集并去重)#
from([1, 2, 2]).union([3, 2]).toArray(); // [1, 2, 3]
✔sequenceEqual
(判断序列相等)#
from([1, 2, 3]).sequenceEqual([1, 2, 3]); // true
from([1, 2, 3]).sequenceEqual([3, 2, 1]); // false(顺序敏感)
buffer
(分批次缓存元素)#
from([1, 2, 3, 4, 5])
.buffer(2)
.toArray(); // [[1, 2], [3, 4], [5]]
skip
(跳过前 N 个元素)#
from([1, 2, 3, 4]).skip(2).toArray(); // [3, 4]
take
(取前 N 个元素)#
from([1, 2, 3, 4]).take(2).toArray(); // [1, 2]
takeFromLast
(取最后 N 个元素)#
from([1, 2, 3, 4]).takeFromLast(2).toArray(); // [3, 4]
✔elementAt
/ elementAtOrDefault
(按索引取元素)#
from([10, 20, 30]).elementAt(1); // 20
from([10, 20, 30]).elementAtOrDefault(5, -1); // -1(索引越界返回默认值)
✔first
/ firstOrDefault
(取首个元素)#
from([5, 6, 7]).first(); // 5
from([]).firstOrDefault(0); // 0
last
/ lastOrDefault
(取末尾元素)#
from([1, 2, 3]).last(); // 3
from([]).lastOrDefault(-1); // -1
single
/ singleOrDefault
(取唯一元素)#
from([5]).single(); // 5
from([1, 2]).singleOrDefault(-1); // 抛出异常(序列包含多个元素)
from([]).singleOrDefault(-1); // -1
6. 查找与索引#
✔indexOf
(查找元素首次出现的位置)#
from(["a", "b", "c", "b"])
.indexOf("b"); // 1(第一个 "b" 的索引)
// 从索引 2 开始查找
from([10, 20, 30, 20])
.indexOf(20, 2); // 3
lastIndexOf
(查找元素最后一次出现的位置)#
from(["a", "b", "c", "b"])
.lastIndexOf("b"); // 3(最后一个 "b" 的索引)
// 限定搜索范围
from([10, 20, 30, 20])
.lastIndexOf(20, 2); // 1(在索引 0-2 范围内查找)
✔contains
(判断是否包含元素)#
from([1, 2, 3]).contains(2); // true
from([1, 2, 3]).contains(4); // false
✔defaultIfEmpty
(空序列返回默认值)#
from([])
.defaultIfEmpty("暂无数据")
.toArray(); // ["暂无数据"]
from([1, 2])
.defaultIfEmpty("默认值")
.toArray(); // [1, 2]
7. 排序与分组#
✔orderBy
/ orderByDescending
(升序/降序排序)#
// 按数值升序
from([3, 1, 2])
.orderBy(x => x)
.toArray(); // [1, 2, 3]
// 按属性降序
from([{ name: "Bob", age: 30 }, { name: "Alice", age: 25 }])
.orderByDescending(x => x.age)
.toArray(); // [{ age: 30 }, { age: 25 }]
✔groupJoin
(分组关联两个序列)#
const customers = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" }
];
const orders = [
{ customerId: 1, product: "书" },
{ customerId: 1, product: "笔" },
{ customerId: 2, product: "电脑" }
];
// 按客户关联订单(左连接)
from(customers)
.groupJoin(
orders,
c => c.id,
o => o.customerId,
(customer, orders) => ({ ...customer, orders: orders.toArray() })
)
.toArray();
/* 输出:
[
{ id: 1, name: "Alice", orders: [{ product: "书" }, { product: "笔" }] },
{ id: 2, name: "Bob", orders: [{ product: "电脑" }] }
]
*/
✔join
(关联两个序列)#
// 内连接示例
from(customers)
.join(
orders,
c => c.id,
o => o.customerId,
(c, o) => `${c.name} 购买了 ${o.product}`
)
.toArray(); // ["Alice 购买了 书", "Alice 购买了 笔", "Bob 购买了 电脑"]
✔toLookup
(转换为键值查找表)#
from(["apple", "banana", "avocado"])
.toLookup(fruit => fruit[0]); // 按键首字母分组
/* 结果:
{
'a': ["apple", "avocado"],
'b': ["banana"]
}
*/
8. 结果转换与输出#
toArray
(转换为数组)#
from("hello")
.toArray(); // ["h", "e", "l", "l", "o"]
✔toObject
(转换为对象)#
from([["name", "Alice"], ["age", 25]])
.toObject(); // { name: "Alice", age: 25 }
// 使用键选择器
from([{ id: 1, value: "A" }, { id: 2, value: "B" }])
.toObject(x => `key_${x.id}`, x => x.value);
// { key_1: "A", key_2: "B" }
toDictionary
(转换为字典)#
from([{ id: 1, name: "A" }, { id: 2, name: "B" }])
.toDictionary(x => x.id);
/* 结果:
{
1: { id: 1, name: "A" },
2: { id: 2, name: "B" }
}
*/
toJSONString
(转换为 JSON 字符串)#
from([1, 2, 3])
.toJSONString(); // "[1,2,3]"
from({ a: 1, b: 2 })
.toJSONString(); // "{\"a\":1,\"b\":2}"
toJoinedString
(连接为字符串)#
from(["a", "b", "c"])
.toJoinedString("|"); // "a|b|c"
write
/ writeLine
(输出到控制台或流)#
from([1, 2, 3])
.write(x => console.log(x)); // 逐行输出 1, 2, 3
from(["hello"])
.writeLine(x => console.log(x + "!")); // 输出 "hello!"
9. 副作用与调试#
doAction
(执行副作用操作)#
在数据流中插入副作用(如日志记录),不影响数据传递:
from([1, 2, 3])
.doAction(x => console.log(`处理元素: ${x}`)) // 输出每个元素
.select(x => x * 2)
.toArray(); // [2, 4, 6]
✔forEach
(遍历执行操作)#
直接遍历元素并执行操作:
from(["a", "b", "c"])
.forEach(x => console.log(x)); // 依次输出 "a", "b", "c"
✔trace
(跟踪元素并输出日志)#
在特定节点打印元素状态:
from([10, 20])
.trace("当前值:") // 控制台输出 "当前值: 10", "当前值: 20"
.toArray();
例子2: doAction
和 trace
一起使用
enumerable.from(self.programWorkflowDefinitions())
.doAction(x => console.log("处理元素", x)) // 输出每个元素
.where(function (x) { return x.name === "HT+LQA" })
.trace("当前值2:") //在这个位置添加一个trace操作符
.toArray()
log
(记录日志)#
记录整个序列的信息:
from([1, 2, 3])
.log("序列内容:")
.toArray(); // 控制台输出 "序列内容: [1, 2, 3]"
catchError
(捕获异常)#
捕获异常并返回备用序列:
from([1, 2, 3])
.select(x => {
if (x === 2) throw "错误";
return x;
})
.catchError(err => from([4, 5])) // 捕获错误后返回新序列
.toArray(); // [1, 4, 5]
✔finallyAction
(最终执行操作)#
无论是否出错,最终执行清理操作:
from([1, 2])
.finallyAction(() => console.log("处理完成!")) // 总会执行
.toArray();
10. 延迟执行与缓存#
force
(强制立即执行)#
强制触发延迟序列的计算:
const lazySeq = from([1, 2, 3]).where(x => x > 1);
lazySeq.force(); // 立即执行查询,返回 [2, 3]
letBind
(绑定中间变量)#
在查询中复用中间结果:
from([1, 2, 3])
.letBind((seq) => ({
sum: seq.sum(),
max: seq.max()
}))
.toObject(); // { sum: 6, max: 3 }
share
(共享序列避免重复计算)#
避免多次枚举导致的重复计算:
const sharedSeq = from(fetchData).share(); // 共享数据源
sharedSeq.take(2).toArray(); // 第一次计算
sharedSeq.take(2).toArray(); // 直接读取缓存
memoize
(缓存结果)#
永久缓存结果:
const memoized = from(fetchExpensiveData).memoize();
memoized.toArray(); // 首次计算并缓存
memoized.toArray(); // 直接读取缓存
11. 杂项与底层操作#
letBind
(通过闭包传递变量)#
在闭包中传递变量并复用:
from([1, 2, 3])
.letBind(context => {
const factor = 10;
return context.select(x => x * factor); // 使用闭包变量
})
.toArray(); // [10, 20, 30]
write
/ writeLine
(流式写入)#
输出到文件流或控制台:
const fs = require("fs");
const stream = fs.createWriteStream("output.txt");
from(["line1", "line2"])
.write(line => stream.write(line + "\n")); // 写入文件
from(["hello"]).writeLine(console.log); // 输出 "hello" 并换行
asEnumerable
(延迟执行转换)#
将类数组对象转换为可枚举序列(延迟执行):
const arrayLike = { 0: "a", 1: "b", length: 2 };
from(arrayLike)
.asEnumerable()
.toArray(); // ["a", "b"]
关键区别说明#
-
intersect
vsunion
:intersect
返回两个序列的交集(共同元素)。union
返回两个序列的并集(合并后去重)。
-
elementAt
vselementAtOrDefault
:elementAt
索引越界时抛出错误。elementAtOrDefault
索引越界时返回默认值。
-
single
vsfirst
:single
要求序列有且仅有一个元素,否则报错。first
直接取第一个元素(允许序列有多个元素)。
-
groupJoin
vsjoin
:groupJoin
类似左连接,返回主序列所有元素并关联子序列的匹配项集合。join
类似内连接,仅返回主序列与子序列匹配的组合。
-
toObject
vstoDictionary
:toObject
通常用于键值对列表转对象。toDictionary
更明确地通过键选择器构建字典结构。
-
write
vswriteLine
:write
按需输出(可自定义格式),writeLine
通常自动换行。
-
doAction
vsforEach
:doAction
用于在数据流中插入副作用(不终止流)。forEach
直接遍历并终止流(类似终端操作)。
-
share
vsmemoize
:share
仅在单次枚举中共享计算结果(重新枚举会重新计算)。memoize
永久缓存结果(后续枚举直接读取缓存)。
-
asEnumerable
的用途:- 将非标准可迭代对象(如类数组、生成器)转换为支持 linqJS 操作的序列。
分类:
Web - javaScript
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
2019-01-21 (二)Knockout 文本与外观绑定
2019-01-21 Knockout案例: 全选
2015-01-21 MVC - 19.Log4net