2015-11-16 2 views
-2

Учитывая список строк и целое число c Я хочу отфильтровать строки, которые являются c-times в списке. Проблема в том, что я не знаю, как взять следующий элемент в моей функции, так как я не могу просто взять первый, потому что тогда функция не будет работать правильно.Отфильтровать строки, которые n-раз в списке

testfunc :: [String] -> Int -> [String] 

testfunc list c    
     | (length(filter (==(head list)) list) == c) = testfunc (filter (/=(head list)) list) c 
+2

не специфичны к этому вопросу: я вижу много вопросов, связанных охранников в последнее время, что приводит к использованию частичных функций и избежать сопоставления с образцом. Интересно, слишком ли в курсе/учебнике/книге уделяется слишком много внимания охранникам, а также программистам-программистам в отношении плохого кода. Преподавателям: рассмотрите вопрос о запрете использования частичных функций (или просто притвориться, что они не существуют в курсе), при обучении Haskell они приносят больше вреда, чем пользы, ИМХО). – chi

+1

@chi, возможно, это связано с вопросами об объятиях ... ^^ – Carsten

ответ

0

Если это нормально для элементов в возвращаемом списке находиться в различных относительных положениях, чем они были в первоначальном списке, то вы можете легко (и с более высокой производительностью) решить эту проблему с комбинацией сортировки, группировка и CONCAT «ING:

testfunc list c = concat $ filter (\p -> length p /= c) $ group (sort list) 

Если вы хотите сделать это ваш путь, вы могли бы использовать drop пропустить первый элемент в списке (это не так, см редактировать):

testfunc list c 
    | list == [] = []    
    | (length(filter (==(head list)) list) == c) = testfunc (filter (/=(head list)) list) c 
    | otherwise = testfunc (drop 1 list) c 

Я нота вполне уверен, что я понял вашу проблему, так это то, что вам нужно?

EDIT: Теперь я понимаю вашу проблему, ваша функция не работает должным образом после первого элемента. Если сохранение порядка важно, вы могли бы попробовать что-то вроде:

testfunc list c = filter (\s -> s `elem` validStrings) list 
      where validStrings = map head $ filter (\p -> length p /= c) $ group (sort list) 
+0

Да, он должен четко сохранять исходные позиции. Просто удалите все строки, которые n-раз в списке. Я попробовал ваше второе решение, но теперь он не завершается, так как я должен проверить, были ли все строки уже обработаны функцией. – craaaft

+0

Хорошо, давайте работать, потому что я тоже начинающий. Это очень длинный список, и число отдельных строк очень велико? Если это так, алгоритм * будет * работать очень плохо. В этом случае, возможно, вам следует создать «Data.Map» с подсчетом на строку, а затем отфильтровать их, просмотрев карту. –

+0

Нет списка, как правило, не большой, и алгоритм также не должен выполнять хорошо. Он просто должен работать. Возможно, ваше 3-е решение действительно работает, я еще не проверял его. – craaaft

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