【问题标题】:Search in 1 million <string Name, int score> pairs using sub-linear time使用亚线性时间在 100 万个 <string Name, int score> 对中搜索
【发布时间】:2018-03-18 23:56:31
【问题描述】:

我有一个包含 100 万对的 JSON 对象。

var student = {[
    {
        name: "govi",
        score: "65"
    },
    {
        name: "dharti",
        score: "80"
    },
    {
        name: "Akash",
        score: "75"
    },............. till 1 million
    ]
};

现在我的关注点如下。

我想构建一个接受用户查询的服务器程序,这样对于每个查询,它都会响应以 s 开头或包含“_s”的前 10 个名称(按分数排名)(例如,“收入”和“yearly_revenue”匹配前缀“rev”)。使用普通的 Jquery 和 json 程序太容易了,但是有一个条件。

条件

查询回答应该在次线性时间内运行(就输入中的姓名数量而言)。

【问题讨论】:

  • 通过name搜索或通过score搜索?您需要通过最可能的搜索模式来索引数组
  • 你想使用多少内存?
  • @gurvinder372 按分数排序并按名称搜索
  • @MineR 内存不是问题,只是想用亚线性时间算法来实现它。
  • 对什么投反对票?

标签: javascript c# jquery .net json


【解决方案1】:

1) 从 nuget 代表添加 Newtonsoft 库

2) 添加以下引用

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

3) 使用此代码

 //JObjectString is your string that contains the values
            JArray ValuesArray = JArray.Parse(JObjectString);

            Dictionary<string, int> SearchDict = new Dictionary<string, int>();

            //here the search term is the query from the user input
            string searchTerm = "govi";

            foreach (var rec in ValuesArray)
            {
                SearchDict.Add(rec["name"].ToString(), Int32.Parse(rec["score"].ToString()));
            }
            //here is the result in javascript array format, return it
            string ResultString = JsonConvert.SerializeObject(SearchDict.Where(o => o.Key == searchTerm | o.Key.Contains(searchTerm)).
                Select(o => o).OrderByDescending(o => o.Value).Take(10).Select(o => o));

【讨论】:

  • 它解决了我的问题。
【解决方案2】:
  1. 按分数降序排列您的数组。这可确保下一步创建已排序的子集,并且比排序(通常重叠)子集更快。

  2. 按字符创建字典。遍历每个名​​称的每个字符并将项目添加到子集中。

  3. 在搜索子字符串(如“rev”)时,您可以检查每个字母的数组,取最短的并可以遍历它,而不是整个数据。

一个例子:

//building the map
let map = Object.create(null);
data
    //.slice()  /if you can't rearrange the items in the original Array
    .sort((a,b) => b.score - a.score)
    .forEach(item => {
        for(let char of new Set(item.name)){
            var arr = map[char] ||| (map[char] = []);
            arr.push(item);
        }
    });

function findSubset(str){
    let best;
    for(let char of new Set(str)){
        //there can be no entry for "rev", if there is no subset for "v" for example
        if(!(char in map)) return [];

        let arr = map[char];
        if(!best || arr.length < best.length)
            best = arr;
    }
    return best || [];
}

function contains(str, limit=Infinity){
    let subset = findSubset(str);
    let results = [];
    for(let i=0; i<subset.length && results.length < limit; ++i){
        let item = subset[i];
        if(item.name.includes(str))
            results.push(item);
    }
    return results;
}

【讨论】:

    【解决方案3】:

    调用 StudentIndex.GetTop10(string s) 将是 O(n),其中 n 是字符串 s 的长度。这会消耗大量内存,但有很多方法可以减少这种情况。 (比如一旦 Node.Top10 的值小于 10 就做一次线性搜索)。

    我让你写树楼。

        public class Student
        {
            public string Name { get; set; }
            public double Score { get; set; }
        }
        public class Node
        {
            public Dictionary<char, Node> Children { get; set; }
            public List<Student> Top10 { get; set; }
        }
        public class StudentIndex
        {
            private Node _root;
    
            public StudentIndex(IEnumerable<Student> students)
            {
                Node root = new Node();
    
                foreach(var student in students)
                {
                    var parts = student.Name.Split(new[] {'_'});
                    foreach(var part in parts)
                    {
                        //you'll add each student to the tree using each part of the name    
                    }
                }
                //set _root
            }
    
            public IEnumerable<Student> GetTop10(string s)
            {
                return GetTop10(s.ToLower(), _root);
            }
    
            private IEnumerable<Student> GetTop10(string s, Node node)
            {
                if (node.Children == null) return node.Top10;
                if (s.Length == 0) return node.Top10;
    
                var c = s[0];
                Node n;
                if (node.Children.TryGetValue(c, out n))
                {
                    return GetTop10(s.Substring(1), n);
                }
                else
                {
                    return Enumerable.Empty<Student>();
                }
            }
        }
    

    【讨论】:

      猜你喜欢
      • 2013-02-10
      • 2016-08-17
      • 1970-01-01
      • 2014-05-02
      • 1970-01-01
      • 2021-08-09
      • 1970-01-01
      • 2018-08-30
      • 2015-07-20
      相关资源
      最近更新 更多