Я думаю, вы делаете это более сложным, чем необходимо. Если я правильно понимаю, вы берете в качестве входных данных список из 3-х кортежей (a, b, c)
, и вы хотите вернуть список из 4-х кортежей (a, b, c, i)
, где i
указывает количество различных a
- значения, которые мы наблюдали.
Таким образом, мы выполняем какое-то отображение, но с аккумулятором. Хотя здесь мы можем использовать конструкции более высокого порядка, давайте нацелимся на использование рекурсии и добавление аккумулятора. Сначала мы можем определить вспомогательную функцию с подписью:
addIndex' :: (Num n, Eq a) => a -> n -> [(a, b, c)] -> [(a, b, c, n)]
где первый параметр, таким образом, является a
-значением предыдущего элемента (здесь мы предполагаем, что мы уже обработали элемент). Второй параметр - это количество элементов, которые мы наблюдали до сих пор, третий элемент - это список элементов, которые нам еще предстоит обработать, а результат - список из 4-х кортежей.
Если список исчерпан, мы можем вернуть пустой список независимо от других переменных:
addIndex' _ _ [] = []
в другом случае, мы должны сравнить предыдущий ключ ap
с текущим ключом a
, и в случае, если они равны, мы возвращаем кортеж с индексом i
в качестве последнего элемента, затем рекурсивно с таким же индексом ; в противном случае мы увеличиваем индекс (до i1 = i + 1
). Мы каждый раз повторяем в конце списка:
addIndex' ap i ((a, b, c): xs) | a == ap = (a, b, c, i) : addIndex' a i xs
| otherwise = (a, b, c, i1) : addIndex' a i1 xs
where i1 = i + 1
Итак, мы получаем функцию:
addIndex' :: (Num n, Eq a) => a -> n -> [(a, b, c)] -> [(a, b, c, n)]
addIndex' _ _ [] = []
addIndex' ap i ((a, b, c): xs) | a == ap = (a, b, c, i) : addIndex' a i xs
| otherwise = (a, b, c, i1) : addIndex' a i1 xs
where i1 = i + 1
Но теперь нам еще нужно обработать первый элемент. Мы знаем, что если список пуст, мы возвращаем пустой список:
addIndex [] = []
в противном случае мы возвращаем в качестве первого кортежа первый в данном списке с индексом 0
, а затем вызываем addIndex'
с оставшимися кортежами и первым ключом в качестве аккумулятора:
addIndex ((a, b, c): xs) = (a, b, c, 0) : addIndex' a 0 xs
поэтому получаем полное решение:
addIndex :: (Num n, Eq a) => [(a, b, c)] -> [(a, b, c, n)]
addIndex [] = []
addIndex ((a, b, c): xs) = (a, b, c, 0) : addIndex' a 0 xs
addIndex' :: (Num n, Eq a) => a -> n -> [(a, b, c)] -> [(a, b, c, n)]
addIndex' _ _ [] = []
addIndex' ap i ((a, b, c): xs) | a == ap = (a, b, c, i) : addIndex' a i xs
| otherwise = (a, b, c, i1) : addIndex' a i1 xs
where i1 = i + 1
Затем мы генерируем, например:
Prelude> addIndex [('a', 1, 4), ('a', 2, 5), ('b', 1, 3), ('b', 0, 2), ('c', 1, 2)]
[('a',1,4,0),('a',2,5,0),('b',1,3,1),('b',0,2,1),('c',1,2,2)]
Но обратите внимание, что мы смотрим только на предыдущий элемент, и, например, например, если после 'c'
появляется клавиша 'a'
, мы снова увеличим счетчик:
Prelude> addIndex [('a', 1, 4), ('a', 2, 5), ('b', 1, 3), ('b', 0, 2), ('c', 1, 2), ('a', 3, 4)]
[('a',1,4,0),('a',2,5,0),('b',1,3,1),('b',0,2,1),('c',1,2,2),('a',3,4,3)]
Эта функция будет работать в линейном времени O (n) , тогда как составленные вами функции будут выполняться в квадратичном времени O (n * 1056) * 2 ) , поскольку добавление выполняется за линейное время (а также last
и т. Д.).