【问题标题】:Return Index List from Dynamic Linq Query从动态 Linq 查询返回索引列表
【发布时间】:2016-03-28 11:57:10
【问题描述】:

我有一个过滤器方法,它采用通用结构数组,执行查询和/或 orderby 和/或使用动态 linq 将表达式作为字符串,并返回匹配索引列表,然后由外部程序。

我最初采用了一种粗略且现成的方法来获取索引列表,只需遍历原始列表并找到该项目与过滤列表中的项目相等的位置,如下所示:

    public static int[] FilterStructs<T>(IList<T> structs, string query = "", string orderBy = "", int topN = 0) where T : struct {            
        var filteredStructs = structs.AsQueryable();
        if (!string.IsNullOrEmpty(query)) filteredStructs = filteredStructs.Where(query);
        if (!string.IsNullOrEmpty(orderBy)) filteredStructs = filteredStructs.OrderBy(orderBy);
        if (topN > 0) filteredStructs = filteredStructs.Take(topN);
        return GetArrayIndexList(structs, filteredStructs.ToArray());
    }

    private static int[] GetArrayIndexList<T>(IList<T> arrMain, T[] arrFiltered) where T : struct {
        List<int> indexes = new List<int>();
        for (int i = 0; i < arrFiltered.Length; i++) {
            for (int j = 0; j < arrMain.Count; j++) {
                if (arrMain[j].Equals(arrFiltered[i])) {
                    indexes.Add(j);
                    break;
                }
            }
        }
        return indexes.ToArray();
    }

但是,当结构数组中甚至包含几千个项目时,这会变得非常缓慢。

我最理想的做法是,最初使用动态选择语句将结构数组投影到具有附加“索引”字段的新数组中,执行过滤,然后仅从选择语句将是微不足道的。

但是,我对如何实现这一点有点空白。

感谢任何建议。

【问题讨论】:

    标签: c# arrays linq


    【解决方案1】:

    如果我理解正确,过滤后的数组元素保证存在于原始数组中,因此您可以将 GetArrayIndexList 主体替换为以下内容。

     private static int[] GetArrayIndexList<T>(IList<T> arrMain, T[] arrFiltered) where T : struct
        {
            return arrFiltered.Select(c=> arrMain.IndexOf(c)).ToArray();
        }
    

    【讨论】:

    • 谢谢。但是,我认为 IndexOf 将使用默认的相等比较器,这就是导致该方法变慢的原因。虽然代码少了很多,但对于一个包含 4000 个项目的数组来说,它仍然需要 1 秒多的时间。
    【解决方案2】:

    虽然这不是我理想的解决方案,但它比我想象的要简单,因为我必须更改查询和 orderby 子句的每个传入字符串表达式以包含投影的实体名称。不过它可以工作,所以暂时可以,直到我有更多时间。

        public static int[] FilterStructs<T>(IList<T> structs, string query = "", string orderBy = "", int topN = 0) where T : struct {
            var withIndex = structs.Select((s, i) => new { index = i, item = s });
            var filteredStructs = withIndex.AsQueryable();
            if (!string.IsNullOrEmpty(query)) filteredStructs = filteredStructs.Where(query);
            if (!string.IsNullOrEmpty(orderBy)) filteredStructs = filteredStructs.OrderBy(orderBy);
            if (topN > 0) filteredStructs = filteredStructs.Take(topN);
            return filteredStructs.Select("index").Cast<int>().ToArray();            
        }
    

    例如,如果我之前的 where 子句是“value = 123”,那么它现在必须变为“item.value = 123”。

    【讨论】:

    • 顺便说一句,这将使用 GetArrayIndexList 方法的执行时间从大约 1500 毫秒减少到 40 毫秒。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-11
    • 2014-05-19
    • 1970-01-01
    • 1970-01-01
    • 2014-01-09
    • 1970-01-01
    • 2018-03-20
    相关资源
    最近更新 更多