Scala: найти вхождения символов из файла - PullRequest
1 голос
/ 01 декабря 2019

Проблема: предположим, у меня есть текстовый файл, содержащий данные типа

TATTGCTTTGTGCTCTCACCTCTGATTTTACTGGGGGCTGTCCCCCACCACCGTCTCGCTCTCTCTGTCA
AAGAGTTAACTTACAGCTCCAATTCATAAAGTTCCTGGGCAATTAGGAGTGTTTAAATCCAAACCCCTCA
GATGGCTCTCTAACTCGCCTGACAAATTTACCCGGACTCCTACAGCTATGCATATGATTGTTTACAGCCT

И я хочу найти вхождения символов 'A', 'T', 'AAA',и т.д. в нем.

Мой подход

  val source = scala.io.Source.fromFile(filePath)
  val lines = source.getLines().filter(char => char != '\n')

  for (line <- lines) {
    val aList = line.filter(ele => ele == 'A')
    println(aList)

  }

Это даст мне вывод наподобие

AAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAA

Мой вопрос Как я могу найти общее число вхождений «A», «T», «AAA» и т.д. здесь? можно использовать карту сократить функции для этого? Как?

Ответы [ 3 ]

2 голосов
/ 01 декабря 2019

Существует даже более короткий путь:

lines.map(_.count(_ == 'A')).sum

Это подсчитывает все A каждой строки и подводит итог.

Кстати, нет filterздесь нужно:

val lines = source.getLines()

И как Лев C упоминается в его комментарии, если вы начнете с Source.fromFile(filePath), это может быть так:

 source.count(_ == 'A')

Как SoleQuantum упоминает в своем комментарии, он хочет, чтобы количество звонков было несколько раз. Проблема здесь в том, что source - это BufferedSource, который не является Collection , а просто Iterator , который может использоваться только (повторяется)один раз.

Итак, если вы хотите использовать source mire, вам нужно сначала один раз преобразовать его в Collection .

Ваш пример:

  val stream = Source.fromResource("yourdata").mkString
  stream.count(_ == 'A') // 48
  stream.count(_ == 'T') // 65

Примечание: строка представляет собой набор символов.

Для получения дополнительной информации проверьте: итераторы

И вот решение дляполучить счетчик для всех Chars:

1046

Или как это было предложено jwvh

stream
    .filterNot(_ == '\n') 
    .groupMapReduce(identity)(_=>1)(_+_))

Это Scala 2,13 , позвольте мнезнать, есть ли у вас проблемы с вашей версией Scala.

Хорошо после последнего обновления вопроса:

stream.toSeq
    .filterNot(_ == '\n')       // filter new lines
    .foldLeft(("", Map.empty[String, Int])){case ((a, m), c ) =>
        if(a.contains(c))
          (a + c, m)
        else
          (s"$c", 
           m.updated(a, m.get(a).map(_ + 1).getOrElse(1)))
      }._2 // you only want the Map -> HashMap( -> 1, CCCC -> 1, A -> 25, GGG -> 1, AA -> 4, GG -> 3, GGGGG -> 1, AAA -> 5, CCC -> 1, TTTT -> 1, T -> 34, CC -> 9, TTT -> 4, G -> 22, CCCCC -> 1, C -> 31, TT -> 7)

Краткое объяснение:

  • В решении используется foldLeft.
  • Начальное значение представляет собой пару:
    • Строка, в которой содержатся действительные символы (нет для начала)
    • a Карта сСтроки и их количество (эмпсевдотерминал в начале)
  • символ отличается. Обновление карты с фактической строкой;новый персонаж теперь фактическая строка.

Довольно сложный, дайте мне знать, если вам нужна дополнительная помощь.

0 голосов
/ 02 декабря 2019

Вы можете использовать метод Partition, а затем просто использовать длину для него.

val y = x.partition(_ == 'A')._1.length
0 голосов
/ 01 декабря 2019

Вы можете получить счет, выполнив следующие действия:

lines.flatten.filter(_ == 'A').size
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...