Определить матрицу int с массивом, списком или картой в OCaml? - PullRequest
3 голосов
/ 27 декабря 2011

Мне нужно определить матрицу типа int как тип. Столбец или строка матрицы представляют city, элемент в матрице представляет distance между городом строки и городом столбца. Размерность матрицы может изменяться (мы можем добавлять или удалять города), но она всегда довольно мала.

Я сомневаюсь среди int array array, int list list и типа с map, который определяется следующим образом:

module MatOrd = struct 
  type t = string * string
  let compare ((a, b): string * string) ((c, d) : string * string) = 
    if Pervasives.compare a  c <> 0
    then Pervasives.compare a c 
    else Pervasives.compare b d
end

module MatMap = Map.Make(MatOrd)

Тогда int MatMap.t может представлять матрицу типа int. Преимущество этого определения заключается в том, что я могу напрямую написать название города в качестве координаты матрицы. Тогда как для int array array и int list list кажется, что я должен запомнить значение координат наизусть ...

Кроме того, правда ли, что мы не можем выполнить сопоставление с массивом? Например, мы не можем написать:

match a_array with
  [| first_element; the_rest_elements |] -> ...

С теми преимуществами и недостатками, которые я упомянул или нет, какой тип вы предлагаете?

1 Ответ

3 голосов
/ 27 декабря 2011

Применимость того или иного типа на самом деле зависит от того, какие операции вы собираетесь выполнять с ним. Что вы будете вычислять с вашим типом?

Например, вы можете воспользоваться матричными операциями, реализованными где-нибудь, например, min-plus умножение , которое может помочь вам с проблемой кратчайшего пути. В этом случае имеет смысл использовать матрицы и иметь отдельную функцию string -> int, которая переводит название города в координаты матрицы. С другой стороны, если вам просто нужно хранилище данных, для которого будет недостаточно вычислений, лучше использовать тип Map, такой как приведенный выше.

Трудно дать очень проницательные ответы, не зная, что вы хотите вычислить, но что касается ваших предложений:

  • помните, списки неизменны, следовательно, int list list имеет ограниченную полезность
  • если вы создаете двумерные массивы, остерегайтесь массивов, которые являются изменяемыми ссылками, и это воздействие обрабатывается соответствующим образом, так что после следующего:

    let a = Array.make 3 0;;
    let a = b;;
    b.(0) <- 42;;
    

    a.(0) равно 42.

    У языка есть страстная стратегия оценки, поэтому еще одно предостережение: не следует создавать массив следующим образом:

    let m = Array.make 2 (Array.make 3 0);;
    m : int array array = [|[|0; 0; 0|]; [|0; 0; 0|]|]
    m.(0).(0) <- 1;;
    - : unit = ()
    m;;
    - : int array array = [|[|1; 0; 0|]; [|1; 0; 0|]|]
    

    Внутренний make вызов оценивается первым, и эти три ссылки разделяются тремя линии вашего внешнего массива. См. FAQ о том, как создавать матрицы.

И, между прочим, вы можете выполнять сопоставление с образцом для массивов (в соответствующем разделе руководства показывает рисунок внизу страницы), но при размещении необходимо учитывать размер вашего массива. переменные образца. К счастью, вы можете использовать _, и, как вы сказали, размер вашего массива довольно мал.

...