Нахождение режима списка int в SML и где это происходит без библиотечных функций - PullRequest
0 голосов
/ 12 марта 2019

Я пытаюсь найти режим или значение, которые встречаются чаще всего.Мне нужна функция вроде:

mode:' 'a list -> (''a * int) list

, и она возвращает режим и место, где она происходит, если нет связи, тогда я возвращаю все вхождения, так что-то вроде:

mode([1,1,2,3,5,8]) ===> [(1,2)]
mode([1,3,5,2,3,5]) ===> [(3,2),(5,2)]
mode([true,false,true,true]) ====>[(true,3)]

Япытаясь сделать это без библиотечных функций в SML.

пока я получил:

fun mode(L)=
if null L then nil
else if hd L= hd (tl L) then 1+mode(hd(tl L))
else mode(tl L);

Я знаю, что это неправильно, я думаю, мне любопытно, как вы оба храните индексыгде происходит режим и что это за режим, и возвращать их в виде кортежей в списке.

1 Ответ

0 голосов
/ 12 марта 2019

Вы пытаетесь решить упражнение во многих частях, выполнив несколько простых упражнений перед ним. Судя по вашему текущему прогрессу, рассматривали ли вы решение некоторых очень похожих упражнений, которые соответствуют конечной цели? Как правило, это хороший совет при решении задач программирования: сведите текущую проблему к более простым и решите их.

Я бы сначала попытался решить эту проблему

  • Построить histogram : ''a list -> (''a * int) list из элементов списка:

    fun histogram [] = ...
      | histogram (x::xs) = ...
    

    Сделайте это, вставив каждый x с count в гистограмму.

    fun insert (x, []) = ...
      | insert (x, (y, count) :: hist) = ...
    

    И напишите несколько тестов, которые вы можете выполнять время от времени.

  • Найдите mode : ''a list -> ''a списка:

    fun mode xs = ... (histogram xs)
    

    Сделайте это, найдя элемент в гистограмме с наибольшим количеством:

    fun findMax [] = ... (* what if the list/histogram is empty? *)
      | findMax [(x, count)] = ...
      | findMax ((x, count) :: (y, count) :: hist) = ...
    

и в конечном итоге попытаться решить эту проблему

  • Когда вы хорошо разберетесь в представлении и навигации по обычным гистограммам рекурсивно, вы можете создать аннотированный histogram : (''a * int * int list) list, который будет содержать не только частоту каждого элемента, но и их позиции в списке ввода:

    fun histogram_helper ([], _) = ...
      | histogram_helper (x::xs, i) = ... histogram_helper (xs, i+1) ...
    

    Сделайте это, вставив каждый x с его count и позицией i вместе с ранее найденными позициями is в гистограмму:

    fun insert (x, i, []) = ...
      | insert (x, i, (y, count, is) :: hist) = ...
    
  • Найдите (возможно, несколько) mode : ''a list -> (''a * int list) list списка:

    fun mode xs = ... (histogram xs)
    

    Сделайте это, найдя (возможно, несколько) элементов в гистограмме с наибольшим количеством:

    fun findMax ([],                     countMax, tmpModes) = ...
      | findMax ((x, count, is) :: hist, countMax, tmpModes) = ...
    

    с countMax : int - частота, повторяемая в tmpModes : (''a * int * int list) list. Здесь countMax и tmpModes являются накапливающими параметры результата . Сделайте это, определив, следует ли выбрасывать (x, count, is) в пользу всех tmpModes, или его следует добавить к tmpModes, или его следует выбирать в пользу всех tmpNodes

    Мне любопытно, как вы оба храните индексы того, где находится режим и что это за режим, и возвращаете их как кортежи в списке.

    Да, это не тривиально. Используя предложенное мной разделение на подзадачи, ответ на этот вопрос зависит от того, находимся ли мы в функции histogram или в функции findMax:

    В histogram вы можете хранить индексы как часть кортежа, который содержит элемент и частоту. В findMax, поскольку вы потенциально можете собирать несколько результатов, вам необходимо отслеживать, какая частота является самой высокой (countMax), и какие режимы временные выбраны (tmpModes) ; подлежит замене или добавлению в последующем рекурсивном вызове.

    Итак, чтобы ответить на ваш вопрос: в параметре накопления.


и небольшая обратная связь с вашим фрагментом кода

fun mode(L)=
if null L then nil
else if hd L= hd (tl L) then 1+mode(hd(tl L))
else mode(tl L);

Использовать сопоставление с образцом вместо null, hd и tl:

fun count_4s [] = 0
  | count_4s (x::xs) = (if x = 4 then 1 else 0) + count_4s xs

fun count_ns ([],    _) = 0
  | count_ns (x::xs, n) = (if x = n then 1 else 0) + count_ns (xs, n)

fun count_12 ([], ones, twos) = (ones, twos)
  | count_12 (x::xs, ones, twos) =
      if x = 1 then count_12 (xs, ones+1, twos) else
      if x = 2 then count_12 (xs, ones, twos+1) else
      count_12 (xs, ones, twos)

fun count_abc ([], result) = result
  | count_abc (x::xs, ((a, ca), (b, cb), (c, cc))) =
      count_abc (xs, if x = a then ((a, ca+1), (b, cb), (c, cc)) else
                     if x = b then ((a, ca), (b, cb+1), (c, cc)) else
                     if x = c then ((a, ca), (b, cb), (c, cc+1)) else
                     ((a, ca), (b, cb), (c, cc)))

Построение гистограммы является своего рода расширением, в котором вместо фиксированного значения, такого как 4, или фиксированного количества таких, как ones и twos, у вас есть целый список из них, и у вас есть динамически искать тот, который у вас есть, x, и определить, нужно ли его добавить в гистограмму или увеличить в гистограмме.

Лучшим способом было бы сделать это с помощью вспомогательной функции, например, если count_abc были созданы с помощью вспомогательной функции,

fun insert_abc (x, ((a, ca), (b, cb), (c, cc))) =
    if x = a then ((a, ca+1), (b, cb), (c, cc)) else
    if x = b then ((a, ca), (b, cb+1), (c, cc)) else
    if x = c then ((a, ca), (b, cb), (c, cc+1)) else
    ((a, ca), (b, cb), (c, cc)))

fun count_abc ([], result) = result
  | count_abc (x::xs, result) =
      count_abc (xs, insert (x, result))

только вместо гистограммы

(''a * int) * (''a * int) * (''a * int)

хочешь

(''a * int) list

и insert должны быть рекурсивными, а не повторяющимися insert_abc.

...