Javascript 2种口味列表中的二进制搜索

Javascript 2种口味列表中的二进制搜索,javascript,string,data-structures,binary-search,Javascript,String,Data Structures,Binary Search,这恰好是在JavaScript中,但问题也适用于其他语言 我有一个很长的单词列表,按字母顺序排列,例如: var myList= [ {word:"abstract", flavor:"old", extraData:...}, {word:"aircraft", flavor:"old", extraData:...}, {word:"airplane", flavor:"new", extraData:...}, {word:"banana", flavor:

这恰好是在JavaScript中,但问题也适用于其他语言

我有一个很长的单词列表,按字母顺序排列,例如:

var myList= [
    {word:"abstract", flavor:"old", extraData:...},
    {word:"aircraft", flavor:"old", extraData:...},
    {word:"airplane", flavor:"new", extraData:...},
    {word:"banana", flavor:"old", extraData:...},
    {word:"calories", flavor:"new", extraData:...},
    ...
];
我的目标是使用某种搜索方法(可能是二进制搜索),以查找以给定子字符串开头的单词数量。在上面的示例中,给定子字符串“air”-结果应该是2

但是,有时我需要搜索整个列表,而有时我只需要搜索“旧”项目(在上面的示例中,每个项目的结果应该是1)

一个明显的解决方案是复制列表,例如:

var wholeList= [
    {word:"abstract", flavor:"old", extraData:...},
    {word:"aircraft", flavor:"old", extraData:...},
    {word:"airplane", flavor:"new", extraData:...},
    {word:"banana", flavor:"old", extraData:...},
    {word:"calories", flavor:"new", extraData:...},
    ...
];

var oldList= [
    {word:"abstract", flavor:"old", extraData:...},
    {word:"aircraft", flavor:"old", extraData:...},
    {word:"banana", flavor:"old", extraData:...},
    ...
];
这当然是非常浪费内存。
此类问题的任何其他/已知解决方案?

要在一个词后过滤:

const search ="air";
const result = myList.filter(word => word.word.substr(0,search.length) === search);
要获得旧的:

const result = myList.filter( word => word.flavor === "old");
两者同时:

const search ="air", flavor = "old";
const result = myList.filter(word => 
   word.flavor === flavor && 
   word.word.substr(0,search.length) === search
);

为了改进这一点,可以使用嵌套贴图作为查找树,或者可以对它们进行预分组。但是,如果您不止一次地搜索,这是值得的。

要查找整个列表中以给定子字符串开头的单词数量,请执行以下操作:

const index = indices[testValue[0]];
for(var i = index[0], len = index[1]; i < len; i += 1) {
  // ...
}
myList.filter(data=>data.word.includes('air')).length

要为仅使用old作为flavor值的列表查找它,请执行以下操作:

myList.filter(data=>data.word.includes('air')&&data.flavor==“old”).length


如果您需要为搜索添加更多约束,只需添加更多的符号和一些逻辑以供过滤器处理。

我想说的是,避免任何需要遍历列表两次的算法。也就是说,每当涉及到庞大的列表时,我更喜欢抛弃任何形式的抽象,使用好的老式循环。只需在列表中迭代并计算匹配的单词,如:

let count = 0;
const testValue = 'air';
const testFlavor = 'old';


for(var i = 0, len = wholeList.length; i < len; i += 1) {
  const current = wholeList[i];

  if (current.word.startsWith(testValue) && current.flavor === testFlavor) {
    count += 1;
  }
}
const indices = {
  a: [0, 2],
  b: [3, 4]
  // ...
}
然后,您只能循环浏览相关部分,而不是整个列表:

const index = indices[testValue[0]];
for(var i = index[0], len = index[1]; i < len; i += 1) {
  // ...
}
const index=index[testValue[0]];
对于(变量i=指数[0],len=指数[1];i
请在c语言中找到以下代码,但这对任何其他语言来说都不是什么大问题:

    public class Item {
        public string Word { get; set; }
        public string Flavour { get; set; }
    }

public int BinarySearch(Item[] ary, string start, string flavor)
        {
            int upperBound = ary.Length - 1, lowerBound = 0, mid,count=0;
            while (lowerBound <= upperBound)
            {
                mid= (int)((lowerBound + upperBound)/ 2);
                if (ary[mid].Word.StartsWith(start))
                {
                    if (!String.IsNullOrEmpty(flavor)) {
                        if (ary[mid].Flavour == flavor) {
                            // if flavor is provided then increment count only if string starts with value and flavor
                            count += 1;
                        }

                    }
                    else
                    {
                        // flavor is not provided so increment cound for whole array
                        count += 1;
                    }
                }
                else if (start[0] < ary[mid].Word[0]) {
                    upperBound -= 1;
                }
                else if (start[0] > ary[mid].Word[0])
                {
                    lowerBound += 1;
                }

            }
            // if method returns 0 means no item starts with specified value
            return count;

        }
公共类项目{
公共字符串字{get;set;}
公共字符串{get;set;}
}
public int-BinarySearch(项[],字符串开始,字符串风格)
{
int上限=ary.Length-1,下限=0,中间,计数=0;
while(lowerboundary[mid].Word[0])
{
lowerBound+=1;
}
}
//if方法返回0表示没有以指定值开头的项
返回计数;
}

这里有一种方法,它将使用二进制搜索作为基本算法,计算以给定子字符串开头的条目数:

函数countEntries(数组、键、前缀){
var l=前缀长度
变量i=0
var j=array.length-1
下变量,上变量,k
而(j-i>1){
k=(i+j)>>1
if(前缀>数组[k][key]){
i=k
}否则{
j=k
}
}
下=j
i=0
j=数组长度-1
而(j-i>1){
k=(i+j)>>1
if(前缀log(countEntries(myList,'word,'air'))
这并不是那么浪费。对象是通过引用复制的,所以只有数组是重复的,这意味着几个kb…问题是“过滤器”是如何在内部实现的。如果它遍历整个列表,可能会花费太长时间…我想这取决于目标是什么。我把它理解为试图找到匹配的子字符串。因此,如果他们搜索“ircra”,它将返回飞机对象,因为该子字符串存在。即使使用已排序的数组,也必须遍历整个数组。现在,如果目标是只匹配前缀子字符串,那么是的,会有更优化的方法来实现这一点。问题是“过滤器”是如何在内部实现的。如果它遍历整个列表,可能会花费太长的时间…@freebud:用例是什么?多久叫一次?