2015-10-15 2 views
1

Итак, у меня возникла проблема с тем, что в основном мне сказали сделать мультимножество или список кортежей. (Char, Int), а затем мне нужно написать функцию, которая берет элемент и вставляет его в этот список, но если в списке уже есть соответствующий кортеж, он увеличивает Int. т. Е. У меня был список [(p, 2), (w, 3)], и я получаю другой w, который должен дать [(p, 2), (w, 4)] Как бы вы это сделали, пробовалоHaskell и манипулирование списком кортежей

listAdd :: Char->Int->ListOfT -> ListOfT 
listAdd c i l 
    |length l == 0 =(c,i):l 
    |fst l == c = (c,i+1):l 

, но это дает нагрузку ошибок, мне нужно, чтобы удалить элемент списка в этой точке и заменить его с (с, я + 1), так как я удалить из списка и как я получаю i + 1? также как вы делаете цикл, который будет проходить через все элементы в списке? И я не могу использовать какой-либо импорт данных. Я знаю, что это задает тонну, но любая помощь будет отличной благодарностью. Neo

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

+0

"я имел список [(р, 2), (ш, 3)] и я получить другую ж ему следует дать [(р, 2), (ш, 4)]", поэтому ваша функция должна иметь подпись 'Char -> ListOfT -> ListOfT', правильно? – mb21

ответ

3

ok Я думаю, что ваша идея неплохая, вам просто нужно получить детали прямо.

петля вы спросили о обычно делаются либо с помощью рекурсии (как список рекурсивной структура, отличная идея) или с некоторыми функциями высшего порядка, как map, filter, foldr, ... что будут скрывать рекурсия от вас (вы могли бы сказать, что они абстрагируют повторяющиеся вещи). В этом случае я думаю, что самый простой способ - это просто начать с того, что вы начали, и использовать прямую рекурсию.

Вот простой вариант (может быть, вы хотите степени), что делает основные вещи:

listAdd :: Char -> [(Char,Int)] -> [(Char,Int)] 
listAdd c [] = [(c,1)] 
listAdd c ((c',i):xs) 
    | c' == c = (c,i+1):xs 
    | otherwise = (c',i) : listAdd c xs 

, как вы можете видеть, что первый случай очень похож на то, что вы имели: если словарь (второй аргумент) является пустым списком, чем вы просто добавляете новый кортеж с вставляемым символом и номером 1

Если нет, то вы проверяете, имеет ли первый элемент в словаре тот же символ (c' здесь), если да, то вы увеличиваете счетчик, и если вы не позволяете этому элементу стоять так, как есть, и рекурсивно искать остальную часть словаря.

Также обратите внимание, что здесь вы можете использовать шаблон, чтобы не только деконструировать словарь в форме head::tail, но и деконструировать голову в (..,..).

Если вы хотите, вы можете использовать @ в там и получить второй случай немного более кратким:

listAdd :: Char -> [(Char,Int)] -> [(Char,Int)] 
listAdd c [] = [(c,1)] 
listAdd c ([email protected](c',i):xs) 
    | c' == c = (c,i+1):xs 
    | otherwise = x : listAdd c xs 

PS: в случае, если Вы задавались вопросом, почему я не использовал свой Int аргумент? Потому что я не знаю, что вы хотите с ним делать, если уже есть значение - вот версия, где я просто добавить его к нему (кажется экономически эффективным):

listAdd :: Char -> Int -> [(Char,Int)] -> [(Char,Int)] 
listAdd c i [] = [(c,i)] 
listAdd c i ([email protected](c',i'):xs) 
    | c' == c = (c,i+i'):xs 
    | otherwise = x : listAdd c i xs 
2

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

Давайте с немного лучше подписью и помощником.

type MyList = [(Char, Int)] 

listAdd :: Char -> MyList -> MyList 
listAdd p l = listAdd' p [] l 

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

Хорошо, что основной костяк. Помощник должен просто сохранить «уже обработанную» часть списка. Давайте посмотрим на него:

listAdd' :: Char -> MyList -> MyList -> MyList 

Во-первых, мы добавим конец рекурсии условие:

listAdd' p left [] = left ++ [(p, 1)] 

Это означает, что если мы не нашли элемент для замены ранее, мы можем просто добавить его на конец.

listAdd' p left (x:right) = if p == fst x 
    then left ++ [(fst x, snd x + 1)] ++ right 
    else listAdd' p (left ++ [x]) right 

Хорошо, теперь мы разделим «правую» часть на первый элемент и на остальные. Давайте посмотрим на if:

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

В качестве дополнительного замечания в конце концов, вы можете легко изменить Char к Eq a => a, чтобы ваша функция работать на любой тип, который может быть непосредственно по сравнению, Char включены.

Смежные вопросы