使用Linqjs像操作数据库一样的操作Json
引言
相信任何程序员在处理数据的时候,都会遇到过庞大的json数据的情况,这时候如果要对json数据进行查询就成了比较麻烦的事,一般人的做法都是循环,可这是一种非常笨效率低的方法,今天我就来介绍一下一款神奇-Linq.js。
概念介绍
LINQ,语言集成查询(Language Integrated Query)是一组用于c#和Visual Basic语言的扩展。它允许编写C#或者Visual Basic代码以查询数据库相同的方式操作内存数据。
而Linq.js就是基于上面的机制,通过javascript来实现的。
注意:
linq.js的api不同版本会有方法的首字母大小写不同的区分,如果报错请更换大小写!!
安装
npm install linqjs
var linq = require('linqjs');
bower install jslinq;
//直接在页面引用
<script src="bower_components/jslinq/linqjs.min.js"></script>
//linqjs有一个jquery的插件版本jquery.linq.js
jquery.linq.js的用法如下
$.Enumerable
(备注,我在github上以及npmjs上搜索到了很多个linqjs的版本,我也不知道哪个是正版的,所以下面的API都是混合的,不一定是你使用的那款linq,还是要看你使用的那款的文档。)
使用
-
选择器
- Select
将序列中的每个元素按照要求放置到一个新的序列中var arr = [1, 2, 3, 4, 5]; var doubled = Enumerable.From(arr).Select(function(t){ return t * 2 }).ToArray(); // [2, 4, 6, 8, 10]
- SelectMany
将序列按照要求放置到一个新的序列中并扁平化var arr = [{Name:"A", Values:[1, 2, 3, 4]}, {Name:"B", Values:[5, 6, 7, 8]}]; var res1 = Enumerable.From(arr).selectMany(function(t){ return t.Values }).ToArray();
- Select
// [1,2,3,4,5,6,7,8]
var res2 = Enumerable.From(arr).selectMany(function(t){ return t.Values }, function(t, u){ return {Name:t.Name, Val:u}}).ToArray();
// [{name:'A',Val:'1'},{name:'A',Val:'2'},{name:'A',Val:'3'},{name:'A',Val:'4'},{name:'B',Val:'5'},{name:'B',Val:'6'},{name:'B',Val:'7'},{name:'B',Val:'8'},]
```
- Take
从序列开始取出对应个数的序列
var arr = [1, 2, 3, 4, 5];
var res = Enumerable.From(arr).Take(2).Toarray(); // [1, 2]
- Skip
跳过对应个数的序列元素,返回剩下的元素
var arr = [1, 2, 3, 4, 5];
var res = Enumerable.From(arr).Skip(2).Toarray(); // [3, 4, 5]
- First
返回序列中的第一个符合条件的元素
var arr = [1, 2, 3, 4, 5];
var t1 = Enumerable.From(arr).First(); // 1
var t2 = Enumerable.From(arr).First(function(t){ return t > 2 }); // 3
- Last
返回序列中的最后一个符合条件的元素
var arr = [1, 2, 3, 4, 5];
var t1 = Enumerable.From(arr).Last(); // 5
var t2 = Enumerable.From(arr).Last(function(t){ return t > 2 }); //5
- Union
使用默认的相等比较器生成两个序列的集合.
var arr1 = [1, 2, 3, 4, 5];
var arr2 = [5, 6, 7, 8, 9];
var res = Enumerable.From(arr1).Union(arr2); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
- Intersect
获取两个集合的交集
var arr1 = [1, 2, 3, 4, 5];
var arr2 = [1, 2, 3];
var res = Enumerable.From(arr1).Intersect(arr2); // [1, 2, 3]
- Except
获取两个集合的差集
var arr1 = [1, 2, 3, 4, 5];
var arr2 = [2, 3, 4];
var res = Enumerable.From(arr1).Except(arr2); // [1, 5]
- Distinct
从一个序列中返回不同的元素。
var arr1 = [1, 2, 2, 3, 3, 4, 5, 5];
var res1 = Enumerable.From(arr1).Distinct(); // [1, 2, 3, 4, 5]
var arr2 = [{Name:"A", Val:1}, {Name:"B", Val:1}];
var res2 = Enumerable.From(arr2).Distinct(function(a, b){ return a.Val == b.Val }); // [{Name:"A", Val:1}]
- Zip
将指定的函数应用于两个序列的相应元素,从而生成一系列结果。
var arr1 = [1, 2, 3, 4];
var arr2 = ["A", "B", "C", "D"];
var res = Enumerable.From(arr1).Zip(arr2, function(a, b){ return {Num:a, Letter:b} });
// [{Num:1, Letter: "A"},{Num:2, Letter: "B"}, {Num:3, Letter: "C"}, {Num:4, Letter: "D"}]
- IndexOf
找出元素出现的位置
var arr = [1, 2, 3, 4, 5];
var index = Enumerable.From(arr).indexOf(2); // 1
- LastIndexOf
从集合尾部开始找出元素的位置
var arr = [1, 2, 3, 4, 5, 3, 4, 5];
var index = Enumerable.From(arr).lastIndexOf(3); // 5
- Remove
移除第一个出现该元素的元素
var arr = [1, 2, 3, 4, 5];
Enumerable.From(arr).Remove(2); // [1, 3, 4, 5]
- RemoveAll
移除所有符合条件的元素
var arr = [1, 2, 3, 4, 5];
Enumerable.From(arr).RemoveAll(function(t){ return t % 2 == 0 }); // [1, 3, 5]
- OrderBy
根据给定的key按照上升趋势排序
var arr = [{Name:"A", Val:1}, {Name:"a", Val:2}, {Name:"B", Val:1}, {Name:"C", Val:2}];
var res1 = Enumerable.From(arr).orderBy(function(t){ return t.Name }).ToArray();
var res2 = Enumerable.From(arr).orderBy(function(t){ return t.Name }, function(a, b){
if(a.toUpperCase() > b.toUpperCase()) return 1;
if(a.toUpperCase() < b.toUpperCase()) return -1;
return 0;
}).ToArray();
//[{Name: "A", Val: 1},{Name: "B", Val: 1},{Name: "C", Val: 2},{Name: "a", Val: 2}]
- OrderByDescending
根据给定的key按照下降趋势排序
var arr = [{Name:"A", Val:1}, {Name:"a", Val:2}, {Name:"B", Val:1}, {Name:"C", Val:2}];
var res = Enumerable.From(arr).OrderByDescending(function(t){ return t.Name });
- ThenBy / ThenByDescending
使用指定的比较器按升序/降序执行序列中元素的后续排序。 ThenBy和ThenByDescending定义为扩展OrderBy和OrderByDescending的输出类型,也是这些方法的返回类型。 这种设计使您能够通过应用任意数量的ThenBy或ThenByDescending方法来指定多个排序条件。
var arr = [{Name:"A", Val:1}, {Name:"a", Val:2}, {Name:"B", Val:1}, {Name:"C", Val:2}];
var res1 = Enumerable.From(arr).OrderBy(function(t){ return t.Val })
.ThenBy(function(t){ return t.Name }).ToArray();
//[{Name: "A", Val: 1},{Name: "B", Val: 1},{Name: "C", Val: 2},{Name: "a", Val: 2}]
var res2 = Enumerable.From(arr).OrderBy(function(t){ return t.Val })
.ThenByDescending(function(t){ return t.Name }).ToArray();
//[{Name: "B", Val: 1},{Name: "A", Val: 1},{Name: "a", Val: 2},{Name: "C", Val: 2}]
var res3 = Enumerable.From(arr).OrderByDescending(function(t){ return t.Val })
.ThenBy(function(t){ return t.Name }).ToArray();
//[{Name: "C", Val: 2},{Name: "a", Val: 2},{Name: "A", Val: 1},{Name: "B", Val: 1}]
- InnerJoin
Correlates the elements of two sequences based on matching keys.
var arr1 = [{Name:"A", Val:1}, {Name:"B", Val:2}, {Name:"C", Val:3}];
var arr2 = [{Code:"A"}, {Code:"B"}, {Name:"C", Code:"C"}];
var res1 = Enumerable.From(arr1).innerJoin(arr2,
function (t) { return t.Name }, // arr1 selector
function (u) { return u.Code }, // arr2 selector
function (t, u) { return { Name: t.Name, Val: t.Val, Code: u.Code } }); // result selector
// using custom comparer
var res2 = Enumerable.From(arr1).innerJoin(arr2,
function (t) { return t.Name }, // arr1 selector
function (u) { return u.Code }, // arr2 selector
function (t, u) { return { Name: t.Name, Val: t.Val, Code: u.Code } }, // result selector
function (a, b) { return a.toUpperCase() == b.toUpperCase() }); // comparer
- GroupJoin
Correlates the elements of two sequences based on equality of keys and groups the results. The default equality comparer is used to compare keys.
var arr1 = [{Name:"A", Val:1}, {Name:"B", Val:2}, {Name:"C", Val:3}];
var arr2 = [{Code:"A"}, {Code:"A"}, {Code:"B"}, {Code:"B"}, {Code:"C"}];
var res1 = Enumerable.From(arr1).groupJoin(arr2,
function(t){ return t.Name }, // arr1 selector
function(u){ return u.Code }, // arr2 selector
function(t, u){ return {Item:t, Group:u} }) ; // result selector
// using custom comparer
var res2 = arr1.groupJoin(arr2,
function(t){ return t.Name }, // arr1 selector
function(u){ return u.Code }, // arr2 selector
function(t, u){ return {Item:t, Group:u} }, // result selector
function(a, b){ return a.toUpperCase() == b.toUpperCase() }); // comparer
- GroupBy
Groups the elements of a sequence according to a specified key Selector function.
var arr = [{Name:"A", Val:1}, {Name:"B", Val:1}, {Name:"C", Val:2}, {Name:"D", Val:2}];
var res = Enumerable.From(arr).groupBy(function(t){ return t.Val });
// [[{Name:"A", Val:1}, {Name:"B", Val:1}], [{Name:"C", Val:2}, {Name:"D", Val:2}]]
res.forEach(function(t){
console.log("Key: " + t.key, "Length: " + t.length);
});
// Key: 1 Length: 2
// Key: 2 Length: 2
- ToDictionary
Creates an object from an array according to a specified key Selector function.
var arr = [1, 2, 3, 4, 5];
var dic = Enumerable.From(arr).toDictionary(function(t){ return "Num" + t }, function(u){ return u });
// dic = {Num5: 5, Num4: 4, Num3: 3, Num2: 2, Num1: 1}
-
Aggregations
- Aggregate
Applies an accumulator function over a sequence.
- Aggregate
var arr = [1, 2, 3, 4, 5];
var sum = Enumerable.From(arr).aggregate(function(a, b){ return a + b }, 0); // 15
- Min
Returns the minimum value in a sequence of values.
var arr1 = [1, 2, 3, 4, 5, 6, 7, 8];
var min1 = Enumerable.From(arr).min(); // 1
var arr2 = [{Name:"A", Val:1}, {Name:"B", Val:2}];
var min2 = Enumerable.From(arr2).min(function(t){ return t.Val }); // 1
- Max
Returns the maximum value in a sequence of values.
var arr1 = [1, 2, 3, 4, 5, 6, 7, 8];
var max1 = Enumerable.From(arr).max(); // 8
var arr2 = [{Name:"A", Val:1}, {Name:"B", Val:2}];
var max2 = Enumerable.From(arr2).max(function(t){ return t.Val }); // 2
- Sum
Computes the sum of a sequence of numeric values.
var arr1 = [1, 2, 3, 4, 5, 6, 7, 8];
var sum1 = Enumerable.From(arr).sum(); // 36
var arr2 = [{Name:"A", Val:1}, {Name:"B", Val:2}];
var sum2 = Enumerable.From(arr2).sum(function(t){ return t.Val }); // 3
-
Predicates
- Where
Filters a sequence of values based on a Predicate.
- Where
var arr = [1, 2, 3, 4, 5];
var res = Enumerable.From(arr).where(function(t){ return t > 2 }) ; // [3, 4, 5]
- Any
Determines whether any element of a sequence exists or satisfies a condition.
var arr = [1, 2, 3, 4, 5];
var res1 = Enumerable.From(arr).any(); // true
var res2 = Enumerable.From(arr).any(function(t){ return t > 5 }); // false
- All
Determines whether all elements of a sequence satisfy a condition.
var arr = [1, 2, 3, 4, 5];
var res = Enumerable.From(arr).all(function(t){ return t < 6 }); // true
- TakeWhile
Returns elements from a sequence as long as a specified condition is true, and then skips the remaining elements.
var arr = [1, 2, 3, 4, 5, 6, 7, 8];
var res = Enumerable.From(arr).takeWhile(function(t){ return t % 4 != 0 }); // [1, 2, 3]
- SkipWhile
Bypasses elements in a sequence as long as a specified condition is true and then returns the remaining elements.
var arr = [1, 2, 3, 4, 5, 6, 7, 8];
var res = Enumerable.From(arr).skipWhile(function(t){ return t % 4 != 0 }) ; // [ 4, 5, 6, 7, 8]
- Contains
Determines whether a sequence contains a specified element.
var arr1 = [1, 2, 3, 4, 5];
var res1 = Enumerable.From(arr).contains(2); // true
var arr2 = [{Name:"A", Val:1}, {Name:"B", Val:1}];
var res2 = Enumerable.From(arr2).contains({Name:"C", Val:1}, function(a, b){ return a.Val == b.Val }) ; // true
-
循环
- Range
Returns a numerical sequence based on the start and end parameters
- Range
var range = Enumerable.From(arr).range(1, 5); // [1,2,3,4,5];
- ForEach
Performs the specified action on each element of the array.
var arr = [1, 2, 3, 4, 5];
Enumerable.From(arr).forEach(function(t){ if(t % 2 ==0) console.log(t); });
- DefaultIfEmpty
Returns the elements of the specified sequence or the specified value in a singleton collection if the sequence is empty.
var arr = [1, 2, 3, 4, 5];
var res = Enumerable.From(arr).where(function(t){ return t > 5 }).defaultIfEmpty(5); // [5]
更多例子
//重复输出5个3
Enumerable.Repeat(3).Take(5);//33333
//输出10开始5个值
Enumerable.Range(10,5);//10,11,12,13,14
//随机
Enumerable.Choice("a","b","c","d").Take(5)//随机输出a,b,c,d
//输出大于7个数
Enumerable.Range(1,10).Count("$>7")//3
//输出指定位置的值
Enumerable.Range(1,10).ElementAt(3)//4
var arr = [
{
name:'abcd',
item:{
list:[1,2,3,4]
}
},
{
name:'123',
item:{
list:[3,4,5,6,7,8]
}
},
{
name:'你好',
item:{
list:[5,6,7,8,9]
}
}
]
//选择name字段
Enumerable.From(arr).Select('$.name');//abcd,123,你好
//输出index为1的
Enumerable.From(arr).Select('$.name').Where('v,i=>i==1');//123
//输出所有的list
Enumerable.From(arr).SelectMany('$.item.list');//123434567856789
//输出去重的list
Enumerable.From(arr).SelectMany('$.item.list').Distinct();//123456789
//倒叙
Enumerable.From(arr).SelectMany('$.item.list').Distinct().OrderByDescending();//987654321
//分组
Enumerable.From(arr).SelectMany('$.item.list').Distinct().GroupBy('$%3').Select("$.Key() + ':' + $.ToString('-')");//1:1-4-7,2:2-5-8,0:3-6-9
/////////////////////////////////
/////////////////////////////////
var Enumerable = require('../linq');
//first step of Lambda Expression
console.log('\nfirst step of Lambda Expression\n');
// Anonymous function
Enumerable.range(1, 3).select(function(value, index) { return index + ':' + value }).log().toJoinedString();
// String like Lambda Expression (arguments => expression)
Enumerable.range(1, 3).select((value, index) => index + ':' + value).log().toJoinedString();
// If the number of arguments is one , can use default iterator variable '$'
Enumerable.range(1, 3).select(i => i * 2).log().toJoinedString();
Enumerable.range(1, 3).select("$*2").log().toJoinedString(); // same
// "" is shortcut of "x => x" (identity function)
Enumerable.range(4, 7).join(Enumerable.range(8, 5), "", "", (outer, inner) => outer * inner).log().toJoinedString();
/////////////////////////////
//Scope of lambda expression
console.log('\nScope of lambda expression\n');
var number = 3;
// Can't Find number | lambda expression can use only global variable
// Enumerable.range(1,10).where("$ == number").log().toJoinedString();
// use anonymous founction, can capture variable
Enumerable.range(1,10).where(function(i){return i == number}).log().toJoinedString();
//////////////////////////////////////////
//from(Object) -> convert to keyvaluePair
console.log('\nfrom(Object) -> convert to keyvaluePair\n');
var object = {foo:"a", "bar":100, "foobar":true};
Enumerable.from(object).forEach(function(obj)
{
console.log(obj.key + ":" + obj.value);
});
//////////////////////////////
//forEach (continue and break)
console.log('\nforEach (continue and break)\n');
Enumerable.repeat("foo", 10).forEach(function(value, index)
{
if (index % 2 == 0) return; // continue
if (index > 6) return false; // break
console.log(index + ":" + value);
});
/////////////////////////////////
//Grouping and ref/value compare
console.log('\nGrouping and ref/value comparen\n');
// ref compare
console.log((new Date(2000, 1, 1) == new Date(2000, 1, 1))); // false
console.log(({ a: 0} == { a: 0 })); // false
console.log("------");
var objects = [
{ Date: new Date(2000, 1, 1), Id: 1 },
{ Date: new Date(2010, 5, 5), Id: 2 },
{ Date: new Date(2000, 1, 1), Id: 3 }
]
// ref compare, can not grouping
Enumerable.from(objects)
.groupBy("$.Date", "$.Id",
function (key, group) { return { date: key, ids: group.toJoinedString(',')} })
.log("$.date + ':' + $.ids").toJoinedString();
console.log("------");
// use fourth argument(compareSelector)
Enumerable.from(objects)
.groupBy("$.Date", "$.Id",
function (key, group) { return { date: key, ids: group.toJoinedString(',')} },
function (key) { return key.toString() })
.log("$.date + ':' + $.ids").toJoinedString();
//////////////////////////////
//Regular Expression matches
console.log('\nRegular Expression matches\n');
// Enumerable.matches return Enumerable<MatchObject>
var input = "abcdefgABzDefabgdg";
Enumerable.matches(input, "ab(.)d", "i").forEach(function(match)
{
for (var prop in match)
{
console.log(prop + " : " + match[prop]);
}
console.log("toString() : " + match.toString());
console.log("---");
});
//////////////////////////////////
//LazyEvaluation and InfinityList
console.log('\nLazyEvaluation and InfinityList\n');
// first radius of circle's area over 10000
var result = Enumerable.toInfinity(1).where(r => r * r * Math.PI > 10000).first();
console.log(result);
/////////////
//Dictionary
console.log('\nDictionary\n');
// sample class
var cls = function (a, b)
{
this.a = a;
this.b = b;
}
var instanceA = new cls("a", 100);
var instanceB = new cls("b", 2000);
// create blank dictionary
var dict = Enumerable.empty().toDictionary();
// create blank dictionary(use compareSelector)
var dict = Enumerable.empty().toDictionary("","",function (x) { return x.a + x.b });
dict.add(instanceA, "zzz");
dict.add(instanceB, "huga");
console.log(dict.get(instanceA)); // zzz
console.log(dict.get(instanceB)); // huga
// enumerable (to keyvaluePair)
dict.toEnumerable().forEach(function (kvp)
{
console.log(kvp.key.a + ":" + kvp.value);
});
/////////////////////////////////////////////
//Nondeterministic Programs
console.log('\nNondeterministic Programs\n');
// from Structure and Interpretation of Computer Programs 4.3.2
var apart = Enumerable.range(1, 5);
var answers = apart
.selectMany(function(baker){ return apart
.selectMany(function(cooper){ return apart
.selectMany(function(fletcher){ return apart
.selectMany(function(miller){ return apart
.select(function(smith){ return {
baker: baker, cooper: cooper, fletcher: fletcher, miller: miller, smith: smith}})})})})})
.where(function(x){ return Enumerable.from(x).distinct("$.value").count() == 5 }).where("$.baker != 5")
.where("$.cooper != 1")
.where("$.fletcher != 1 && $.fletcher != 5")
.where("$.miller > $.cooper")
.where("Math.abs($.smith - $.fletcher) != 1")
.where("Math.abs($.fletcher - $.cooper) != 1");
answers.selectMany("").log("$.key + ':' + $.value").toJoinedString();