2010-08-08 10 views
6

Acabo de comenzar a implementar mi primer programa de mediana escala en D 2.0 después de leer el libro de Andrei The D Programming Language. Uno de los primeros problemas que encontré fue el uso de la biblioteca std.algorithm con una matriz asociativa incorporada. Por ejemplo:rangos de matrices asociativas en D 2

#!/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); 
} 

ha parecido una cosa bastante simple para mí, esperando que la iteración en la inter produciría la entrada única "dos". Sin embargo, me sale este error del compilador:

./test.d(20): Error: template std.algorithm.setIntersection(alias less = "a < b",Rs...) if (allSatisfy!(isInputRange,Rs)) does not match any function template declaration

./test.d(20): Error: template std.algorithm.setIntersection(alias less = "a < b",Rs...) if (allSatisfy!(isInputRange,Rs)) cannot deduce template function from argument types !()(int[string],int[string])

me puede ver que el incorporado en la matriz asociativa no parece ofrecer ninguna versión de la gama de usar con los algoritmos std.

¿Echo de menos algo? Haciendo algo mal? Si no, ¿es esto una omisión flagrante? ¿Hay alguna razón por la cual esto no está disponible?

+1

¿Qué quiere decir con la intersección de dos matrices asociativas? ¿Qué pasa si 'map1 = [" red ": 4," blue ": 6]' y 'map2 = [" blue ": 2," green ": 1]'? – kennytm

+0

En C++, un ejemplo cercano sería 'std :: map '. En este caso, 'std :: set_intersection' toma el tipo de iterador que esencialmente hace referencia al valor_type de' std :: pair '. La std :: set_intersection usa '<' en el value_type que compara tanto la clave como el valor. Entonces, en su ejemplo, esperaría que la intersección estuviera vacía. – aligature

Respuesta

6

Utilice esta:

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

¿No es necesario ordenar los rangos? – dsimcha

+1

Los documentos ciertamente dicen que los rangos que pasas a 'setIntersection()' necesitan ser ordenados primero por cualquier predicado que se le dé (que pasa a ser '" a

0

usted puede obtener las claves o los valores de una matriz asociativa.

Para llegar a la intersección de los valores, utilice

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

Para llegar a la intersección con las teclas, utilice

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

no creo que se puede obtener acceso a una serie que contiene el clave, pares de valores como con un C++ std :: map.

Ver http://www.digitalmars.com/d/2.0/hash-map.html

5

Nota que std::map en C++ es un ordenados estructura de datos, mientras que una matriz asociativa en D es desordenada. std.algorithm.setIntersection asume un rango de ordenado, por lo que no puede usar esta función hasta que haya convertido la matriz asociativa en un rango ordenado, p. (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))); 
} 

Pero este método es ineficiente - se necesita O (N log N) para ordenar un rango.

Un método más eficiente es como para escribir su propia rutina de intersección, que sólo toma 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, " "); 

} 

Sin embargo, debido opApply no cuenta como un rango de entrada, toda la gama los algoritmos no funcionarán con esto. (No sé cómo se puede convertir esto en un rango de entrada.)

Cuestiones relacionadas