范围来自D 2中的关联数组

时间:2010-08-08 19:04:23

标签: d associative-array

在阅读了Andrei的书 D编程语言之后,我刚刚开始在D 2.0中实现我的第一个中等规模的程序。我遇到的第一个问题之一是使用带有内置关联数组的std.algorithm库。例如:

#!/usr/bin/env rdmd

import std.stdio;
import std.algorithm;

void main()
{
   alias int[string] StringHashmap;

   StringHashmap map1;
   map1["one"] = 1;
   map1["two"] = 2;
   writefln("map1: %s", map1);

   StringHashmap map2;
   map2["two"] = 2;
   map2["three"] = 3;
   writefln("map2: %s", map2);

   auto inter = setIntersection(map1, map2);
}

对我来说这似乎很简单,期望在inter上迭代会产生单个“两个”条目。但是,我得到了这个编译错误:

  

./ test.d(20):错误:模板   std.algorithm.setIntersection(别名   less =“a< b”,Rs ......)if   (allSatisfy!(isInputRange,Rs))   不匹配任何功能模板   声明

     

./ test.d(20):错误:模板   std.algorithm.setIntersection(别名   less =“a< b”,Rs ......)if   (allSatisfy!(isInputRange,Rs))不能   从参数中推导出模板函数   types!()(int [string],int [string])

我可以看到内置的关联数组似乎没有提供与std算法一起使用的任何版本的范围。

我错过了什么吗?做错了什么?如果没有,这是一个明显的遗漏吗?是否有一些原因可以解决这个问题?

3 个答案:

答案 0 :(得分:6)

使用此:

auto inter = setIntersection(map1.keys, map2.keys);

答案 1 :(得分:5)

请注意,C ++中的std::map排序数据结构,而D中的关联数组是无序std.algorithm.setIntersection假设排序范围,因此在将关联数组转换为排序范围之前,不能使用此函数,例如(result

import std.typecons;
import std.array;
import std.algorithm;
import std.stdio;

auto byItemSorted(K,V)(V[K] dict) {
   auto app = appender!(Tuple!(K,V)[])();
   foreach (k, v; dict)
     app.put(tuple(k, v));
   auto res = app.data;    // if there's byItem() we don't need this appender stuff.
   sort(res);
   return res;
}

auto dictIntersection(K,V)(V[K] map1, V[K] map2) {
  return setIntersection(byItemSorted(map1), byItemSorted(map2));
}

void main () {
   auto map1 = ["red":4, "blue":6],
        map2 = ["blue":2, "green":1],
        map3 = ["blue":6, "purple":8];
   writeln("map1 & map2 = ", array(dictIntersection(map1, map2)));
   writeln("map1 & map3 = ", array(dictIntersection(map1, map3)));
}

但是这种方法效率很低 - 需要O(N log N)来对范围进行排序。

更有效的方法就是编写自己的交集例程,只需要O(N)(result):

import std.stdio;

struct DictIntersection(K,V) {
  V[K] m1, m2;
  this(V[K] map1, V[K] map2) { m1 = map1; m2 = map2; }
  int opApply(int delegate(ref K, ref V) dg) {
    int res = 0;
    foreach (k, v; m1) {
      V* p = k in m2;
      if (p && v == *p) {
        res = dg(k, v);
        if (res)
          break;
      }
    }
    return res;
  }
}
DictIntersection!(K,V) dictIntersection(K,V)(V[K] map1, V[K] map2) {
  return typeof(return)(map1, map2);
}

void main () {
   auto map1 = ["red":4, "blue":6],
        map2 = ["blue":2, "green":1],
        map3 = ["blue":6, "purple":8];

   write("map1 & map2 = ");
   foreach (k, v; dictIntersection(map1, map2)) write(k, "->", v, " ");
   write("\nmap1 & map3 = ");
   foreach (k, v; dictIntersection(map1, map3)) write(k, "->", v, " ");

}

但是,由于opApply不算作输入范围,因此所有范围算法都不适用。 (我不知道如何将其作为输入范围。)

答案 2 :(得分:0)

您可以从关联数组中获取键或值。

要获取值的交集,请使用

auto inter = setIntersection(map1.values, map2.values);
foreach (i; inter) {
   writeln(i);
}

要获得键上的交叉点,请使用

auto inter = setIntersection(map1.keys, map2.keys);
foreach (i; inter) {
   writeln(i);
}

我认为您无法访问包含键值对的范围,例如C ++ std :: map。

请参阅http://www.digitalmars.com/d/2.0/hash-map.html