Linq To JavaScript
C#的Linq
好久没写文章了,平时的日子里感觉也没啥好写,一般不懂的问题查下百度也能解决.但是昨天感觉C# WebMVC 的前端里要处理Array对象,老写for感觉好麻烦呀.也想像处理C# List对象一样处理Array.于是乎就随便尝试了下.自己写个Linq吧.
写完第一个Where后感觉还行,写到一半才发现有大佬已经写出来了.后面也随便写写,毕竟自己写的自己用起来也比较习惯.
写的不好,但大致还挺像这么一回事的.后续我也会完善更新它.希望对大家有用.
大佬的GitHub: https://github.com/crpietschmann/jslinq
大佬的JS代码: https://github.com/crpietschmann/jslinq/blob/master/Website/scripts/JSLINQ.js
用法
基本上跟C# 的Linq差不多,但JS的特性呢会跟C#不一样,比C#还灵活一点吧,毕竟不是强类型语言.
var arr =new Array(1,2,3,4,5,5,6,7);
var res = arr.Where(m=>m>2);//res=[3,4,5,5,6,7]
var res1 = arr.Select(function(m){
return {value:m};
});
//res1=[{value:1},{value:2},{value:3},{value:4},{value:5},{value:5},{value:6},{value:7}]
arr=[{n:'n1',id:1},{n:'n1',id:2},{n:'n3',id:3},{n:'n4',id:4}];
res= arr.GroupBy(m=>m.n).Select(m=>m.Key);
//res=['n1','n3','n4']
//还有其他的函数就不一一例举了
Linq to JS代码
//保守写法,最好将函数写成传统function(m){return m}的格式
!function () {
//条件查询
Array.prototype.Where = function (f) {
let arr = new Array();
for (var i = 0; i < this.length; i++) {
if (f(this[i])) {
arr.push(this[i]);
}
}
return arr;
};
//查询转换
Array.prototype.Select = function (f) {
let arr = new Array();
for (var i = 0; i < this.length; i++) {
let val = f(this[i]);
if (val === undefined) {
continue;
}
if (typeof (val) === 'function') {
arr.push(this[i]);
continue;
}
arr.push(val);
}
//arr=new Array({n:'n1',id:1},{n:'n2',id:2},{n:'n3',id:3},{n:'n4',id:4})
//arr=new Array(1,2,3,4,5,6,7)
//稍微注意的是返回新对象时要使用function(m){ return {filde:m.xx}}格式
return arr;
};
//求和
Array.prototype.Sum = function (f) {
let num = 0;
for (var i = 0; i < this.length; i++) {
let val = f(this[i]);
switch (typeof (val)) {
case 'bigint':
case 'number':
num += val;
break;
case 'function':
try {
if (typeof (this[i]) === 'number' || typeof (this[i]) === 'bigint') {
num += this[i];
}
} catch (e) {
console.error(e);
}
break;
default:
break;
}
}
return num;
};
//获取数量
Array.prototype.Count = function (f) {
if (f === undefined || typeof (f) != 'function') return this.length;
let count = 0;
for (var i = 0; i < this.length; i++) {
if (f(this[i])) {
count++;
}
}
return count;
};
//判断是否包含
Array.prototype.Contains = function (f) {
for (var i = 0; i < this.length; i++) {
if (f(this[i])) {
return true;
}
}
return false;
}
//取第一个
Array.prototype.First = function (f) {
if ((typeof (f) != 'function' || f === undefined) && this.length > 0) {
return this[0]
}
for (var i = 0; i < this.length; i++) {
if (f(this[i])) {
return this[i];
}
}
return undefined;
};
//取符合条件的最后一个 f可省略
Array.prototype.Last = function (f) {
if ((typeof (f) != 'function' || f === undefined) && this.length > 0) {
return this[this.length - 1]
}
for (var i = this.length - 1; i >= 0; i--) {
if (f(this[i])) {
return this[i];
}
}
return undefined;
};
//模拟C#中IGrouping GroupBy的Key
Array.prototype.Key = undefined;
//分组
Array.prototype.GroupBy = function (f) {
if (f === undefined || typeof (f) != 'function') {
f = function (m) {
switch (typeof (m)) {
case 'object':
return Object.values(m);
case 'undefined':
return 'undefined';
default:
return m;
}
}
}
let arr = new Array();
let keys = new Array();
let values = new Array();
for (var i = 0; i < this.length; i++) {
let val = f(this[i]);
let index = keys.indexOf(val);
if (index >= 0) {
values[index].push(this[i]);
} else {
keys.push(val);
var vs =new Array();
vs.push(this[i]);
values.push(vs);
}
}
for (var i = 0; i < keys.length; i++) {
let gs = values[i];
gs.Key = keys[i];
arr.push(values[i]);
}
return arr;
};
//排序原始方法
//bigint
//number
//string
function orderby(vs, f, desc) {
if (f == undefined) {
f = function (m) {
return m;
}
}
let arr = new Array();
let keys = new Array();
let table = new Array();
for (var i = 0; i < vs.length; i++) {
let k = f(vs[i]);
switch (typeof (k)) {
case 'bigint':
case 'number':
case 'string':
case 'object':
keys.push(k);
table.push({ key: k, value: vs[i] });
break;
case 'function':
try {
if (typeof (k) === 'number' || typeof (k) === 'bigint' || typeof (k) === 'string') {
keys.push(k);
table.push({ key: k, value: vs[i] });
}
} catch (e) {
console.error(e);
}
break;
default:
break;
}
}
//keys = keys.sort();//不靠谱
for (var i = 0; i < keys.length; i++) {
for (var j = i + 1; j < keys.length; j++) {
if (keys[i] > keys[j]) {
let t = keys[i];
keys[i] = keys[j];
keys[j] = t;
}
}
}
if (desc) {
keys = keys.reverse();
}
while (keys.length > 0) {
let k = keys[0];
for (var i = 0; i < table.length; i++) {
if (table[i].key === k) {
arr.push(table[i].value)
keys.splice(0, 1);
table.splice(i, 1);
break;
}
}
}
return arr;
}
//顺序排序
Array.prototype.OrderBy = function (f) {
return orderby(this, f, false);
};
//倒序排序
Array.prototype.OrderByDesc = function (f) {
return orderby(this, f, true);
};
//Join 左边连接右边
//arr=new Array({n:'n5',id:5},{n:'n1',id:2},{n:'n3'},{n:'n4',id:4})
//arr1=new Array({n:'n5',age:51},{n:'n5',age:12},{n:'n3'},{n:'n4',age:44})
//arr.JoinArray(arr1,(m,n)=>m.n==n.n)
Array.prototype.JoinArray = function (vs, f) {
if (f === undefined || typeof (f) != 'function') {
f = function (m) {
switch (typeof (m)) {
case 'object':
return Object.values(m);
case 'undefined':
return 'undefined';
default:
return m;
}
}
}
let arr = new Array();
let keys = new Array();
let values = new Array();
for (var i = 0; i < this.length; i++) {
keys.push(this[i]);
let items = new Array();
for (var j = 0; j < vs.length; j++) {
if (f(this[i], vs[j])) {
items.push(vs[j]);
}
}
values.push(items);
}
for (var i = 0; i < keys.length; i++) {
let gs = new Array(values[i]);
gs.Key = keys[i];
arr.push(gs);
}
return arr;
};
//移除特定对象的第一个匹配项
Array.prototype.Remove = function (obj) {
let num = 0;
for (var i = 0; i < this.length; i++) {
if (this[i] === obj) {
this.splice(i, 1);
num++;
}
}
return num;
};
//跳过指定的数量的序列中的元素,然后返回剩余元素。
Array.prototype.Skip = function (count) {
let arr = new Array();
count = Math.abs(count);
count--;
if (count < 0) {
count == 0;
}
//count = this.length > count ? count : this.length;
for (let i = count; i < this.length; i++) {
arr.push(this[i]);
}
return arr;
};
//从序列的开头返回指定的数量的连续元素。
Array.prototype.Take = function (count) {
let arr = new Array();
count = Math.abs(count);
count = this.length > count ? count : this.length;
for (let i = 0; i < count; i++) {
arr.push(this[i]);
}
return arr;
};
//序列中返回的最小值。
Array.prototype.Min = function (f) {
let min = undefined;
for (var i = 0; i < this.length; i++) {
let val = f(this[i]);
switch (typeof (val)) {
case 'bigint':
case 'number':
case 'string':
if (min > val && min != undefined) {
min = val
}
if (min === undefined) {
min = val
}
break;
case 'function':
try {
if (typeof (this[i]) === 'number' || typeof (this[i]) === 'bigint' || typeof (this[i]) === 'string') {
if (min > val && min != undefined) {
min = val
}
if (min === undefined) {
min = val
}
}
} catch (e) {
console.error(e);
}
break;
default:
break;
}
}
return min;
};
//序列中返回的最大值。
Array.prototype.Max = function (f) {
let max = undefined;
for (var i = 0; i < this.length; i++) {
let val = f(this[i]);
switch (typeof (val)) {
case 'bigint':
case 'number':
case 'string':
if (max < val && max != undefined) {
max = val
}
if (max === undefined) {
max = val
}
break;
case 'function':
try {
if (typeof (this[i]) === 'number' || typeof (this[i]) === 'bigint' || typeof (this[i]) === 'string') {
if (max < val && max != undefined) {
max = val
}
if (max === undefined) {
max = val
}
}
} catch (e) {
console.error(e);
}
break;
default:
break;
}
}
return max;
};
//将元素插入 Array 的指定索引处。
Array.prototype.Insert = function (index, item) {
let arr = new Array();
for (var i = 0; i <= this.length; i++) {
if (i < index) {
arr.push(this[i]);
} else if (i > index) {
arr.push(this[i - 1]);
} else {
arr.push(item);
}
}
return arr;
};
//通过使用默认的相等比较器生成的两个序列的并集,并且去重。f的返回格式建议为Array对象
Array.prototype.Union = function (vs, f) {
let arr = new Array();
if (f === undefined || typeof (f) != 'function') {
f = function (m) {
switch (typeof (m)) {
case 'object':
return Object.values(m);
case 'undefined':
return 'undefined';
default:
return m;
}
//return Object.values(m);//对值不对键,希望少有值相同,键不同的对象吧
}
}
if (!Array.isArray(vs)) {
vs = Array.from(vs);
}
if (this.length > 0) {
arr.push(this[0]);
} else if (vs.length > 0) {
arr.push(vs[0]);
}
function additem(items) {
for (var i = 0; i < items.length; i++) {
let isin = true;
for (var j = 0; j < arr.length; j++) {
if (f(items[i]) === undefined) {
isin = false;
break;
}
if (f(items[i]).toString() == f(arr[j]).toString()) {
isin = false;
break;
}
}
if (isin) {
arr.push(items[i]);
}
}
}
additem(this);
additem(vs);
return arr;
};
//通过使用默认的相等比较器对值进行比较,生成两个序列的差集。
Array.prototype.Except = function (vs, f) {
let arr = new Array();
if (f === undefined || typeof (f) != 'function') {
f = function (m) {
switch (typeof (m)) {
case 'object':
return Object.values(m);
case 'undefined':
return 'undefined';
default:
return m;
}
}
}
for (var i = 0; i < this.length; i++) {
let isin = true;
for (var j = 0; j < vs.length; j++) {
if (f(this[i]) === undefined || undefined === f(vs[j])) {
isin = false;
break;
}
if (f(this[i]).toString() == f(vs[j]).toString()) {
isin = false;
break;
}
}
if (isin) {
arr.push(this[i]);
}
}
return arr;
};
//通过使用的默认相等比较器对值进行比较,生成两个序列的交集。
Array.prototype.Intersect = function (vs, f) {
let arr = new Array();
if (f === undefined || typeof (f) != 'function') {
f = function (m) {
switch (typeof (m)) {
case 'object':
return Object.values(m);
case 'undefined':
return 'undefined';
default:
return m;
}
}
}
for (var i = 0; i < this.length; i++) {
for (var j = 0; j < vs.length; j++) {
if (f(this[i]) === undefined || undefined === f(vs[j])) {
break;
}
if (f(this[i]).toString() == f(vs[j]).toString()) {
arr.push(this[i]);
break;
}
}
}
return arr;
};
//对象数组转2维数组 ks=>[ks.x1,ks.x2]
Array.prototype.TwoDimensional = function (ks, totitle) {
let keys = new Array();
if (this.length === 0) {
return keys;
}
keys = Object.keys(this[0]);
let obj = new Object();
keys.forEach(function (k) {
obj[k] = k;
})
if (typeof (ks) === 'function') {
keys = ks(obj);
}
let vs = new Array();
if (totitle) {
vs.push(keys);
}
let thisme = this;
for (let i = 0; i < this.length; i++) {
let value = new Array();
keys.forEach(function (k) {
//debugger
value.push(thisme[i][k]);
});
vs.push(value);
}
return vs;
};
//二维数组转对象数组
Array.prototype.ToObject = function (iskey) {
if (typeof (iskey) === 'undefined') {
iskey = true;
}
let arr = new Array();
if (this.length === 0 || !Array.isArray(this[0])) {
return arr;
}
let keys;
if (iskey) {
keys = this[0];
} else {
keys = Object.keys(this[0]);
}
for (var i = 1; i < this.length; i++) {
let obj = new Object();
for (var j = 0; j < keys.length; j++) {
obj[keys[j]] = this[i][j];
}
arr.push(obj);
}
return arr;
}
//行转列
//newCols 要新增的列名
//oldCol 要拆分的列名
//pivotCol 要填充转换的列名,该列的值要为number类型
Array.prototype.RowToCol = function (newCols, oldCol, pivotCol) {
//arr = [{name:'小明',subject:'语文',score:96},{ name: '小明', subject: '数学', score: 98 },{ name: '小明', subject: '英语', score: 96 },{ name: '大花', subject: '语文', score: 92 },{ name: '大花', subject: '数学', score: 96 },{ name: '大花', subject: '英语', score: 98 }]
//m=>['','',''].Contains(m.subject),m=>m.Sum(m.score)
let vs = new Array();
let newHeads = new Array();
if (this.length === 0 || !Array.isArray(newCols)) {
return newHeads;
}
for (var i = 0; i < this[0].length; i++) {
if (this[0][i].indexOf(oldCol) > -1 || this[0][i].indexOf(pivotCol) > -1) {
continue;
}
newHeads.push(this[0][i]);
}
let objs = this.ToObject();
let group = objs.GroupBy(function (m) {
let g = '';
newHeads.forEach(function (item) {
g += m[item];
});
return g;
});
let bycols = Array.from(newHeads);
newCols.forEach(function (item) {
newHeads.push(item);
});
vs.push(newHeads);
for (var i = 0; i < group.length; i++) {
let row = new Array();
for (var j = 0; j < bycols.length; j++) {
row.push(group[i].First()[bycols[j]]);
}
for (var j = 0; j < newCols.length; j++) {
row.push(group[i].Where(m => m[oldCol] == newCols[j]).Sum(m => m[pivotCol]));
}
vs.push(row);
}
return vs;
}
//列转行
//rowNames 要转成列值的行,底下的值要为number
//newRowName 转成列的名字
//valueName 值的行名称
Array.prototype.ColToRow = function (rowNames, newRowName, valueName) {
let vs = new Array();
let newHeads = new Array();
if (this.length === 0 || !Array.isArray(rowNames)) {
return newHeads;
}
for (var i = 0; i < this[0].length; i++) {
if (rowNames.Contains(m => m === this[0][i])) {
continue;
}
newHeads.push(this[0][i]);
}
let objs = this.ToObject();
let group = objs.GroupBy(function (m) {
let g = '';
newHeads.forEach(function (item) {
g += m[item];
});
return g;
});
let bycols = Array.from(newHeads);
newHeads.push(newRowName);
newHeads.push(valueName);
vs.push(newHeads);
for (var i = 0; i < group.length; i++) {
let arr = new Array();
bycols.forEach(function (item) {
arr.push(group[i].First()[item]);
});
for (var j = 0; j < rowNames.length; j++) {
let row = Array.from(arr);
row.push(rowNames[j]);
let val = group[i].Sum(m => m[rowNames[j]]);
row.push(val);
vs.push(row);
}
}
return vs;
}
//递归遍历子级
Array.prototype.Recursion = function (func, field) {
for (let i = 0; i < this.length; i++) {
func(this[i]);
try {
if (Array.isArray(this[i][field])) {
this[i][field].Recursion(func, field);
}
} catch (e) {
console.warn(e);
}
}
};
//递归组装
Array.prototype.RecursionChildren = function (bool_where_func, children_field, list) {
for (let i = 0; i < this.length; i++) {
if (!Object.keys(this[i]).Contains(children_field)) {
Object.defineProperty(this[i], children_field, {
configurable: true,
enumerable: true,
writable: true,
value: new Array()
});
}
let list_1 = new Array();
for (let j = 0; j < list.length; j++) {
//bool_where_func返回Bool类型,需要传两参数(m,n)=>...
if (bool_where_func(this[i], list[j])) {
list_1.push(list[j]);
}
}
this[i][children_field] = list_1;
if (this[i][children_field].length > 0) {
this[i][children_field].RecursionChildren(bool_where_func, children_field, list);
}
}
};
//var arr = [{ n: '1', id: 1, pid: null, ch: [{ n: '2', id: 2, pid: 1, ch: [{ n: '3', id: 3, pid: 2}]}]}];
//var arr = [{ n: '1', id: 1, pid: null} ,{ n: '2', id: 2, pid: 1},{ n: '3', id: 3, pid: 2}];
//递归返回父级,this是非树形结构
Array.prototype.RecursionParent = function (obj, field, pfield) {
let arr = new Array();
for (let i = 0; i < this.length; i++) {
if (this[i][field] === obj[pfield]) {
arr.push(this[i]);
arr = arr.concat(this.RecursionParent(this[i], field, pfield));
return arr;
}
}
return arr;
};
//递归返回父级,this是树形结构
Array.prototype.RecursionParentTree = function (obj, cfield, field, pfield) {
let arr = new Array();
for (let i = 0; i < this.length; i++) {
arr.push(this[i]);
//if (!Object.keys(this[i]).Contains(m => m === cfield)) {
// continue;
//} else
if (this[i][field] === obj[pfield]) {
return arr;
} else if (Array.isArray(this[i][cfield])) {
arr = arr.concat(this[i][cfield].RecursionParentTree(obj, cfield, field, pfield));
} else {
return [];
}
}
return arr;
}
}();