Linq To Js

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;
    }
}();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值