Как подсчитать вхождения разных персонажей и вернуть их всех в виде таблицы - PullRequest
1 голос
/ 15 мая 2019

Вот точный вопрос:

COUNT-BASES считает количество баз каждого типа в либо одноцепочечная или двухцепочечная ДНК и возвращает результат как таблица.

(COUNT-BASES '((G C) (A T) (T A) (C G))) should return
((A 2) (T 2) (G 2) (C 2))
(COUNT-BASES '(A G T A C T C T)) should return
((A 2) (T 3) (G 1) (C 2)).

Я написал функцию my-count, которая возвращает вхождения одного символа, но не может понять, как применить это для всех 4 букв (A T G C) и вернуть в виде таблицы.

;returns the count of a base (a) from a list (L)
(defun my-count (a L)
  (cond ((null L) 0)
        ((equal a (car L)) (+ 1 (my-count a (cdr L))))
        (t (my-count a (cdr L)))))

Ответы [ 2 ]

1 голос
/ 16 мая 2019

Чисто императивная версия кода может выглядеть следующим образом:

(defun count-bases (bases)
  (let ((atgc (vector 0 0 0 0)))
    (dolist (dna bases (map 'list #'list #(a t g c) atgc))
      (dolist (base (if (listp dna) dna (list dna)))
        (incf (svref atgc (position base #(a t g c))))))))
  1. Создать вектор из 4 элементов, в котором хранятся счетчики для всех баз.
  2. Итерировать по всемзаписей в списке и итерации по всем базам в каждой записи: обычно это делается с помощью alexandria:ensure-list, но здесь это записано простым текстом.
  3. Найдите положение каждой базы в буквальном векторе #(a t g c)вектор символов.Используйте возвращаемую позицию, чтобы увеличить связанный счетчик.
  4. Наконец (последняя форма в DOLIST), построить возвращаемое значение в ожидаемом формате:

    MAP как для #(a t g c), так и для вектора счетчика atgc, построить 'list, применив функцию #'list к каждой паре элементов, взятых из обеих последовательностей: например, первая итерацияпосещает a и счетчик для базы a и вызывает на них #'list, что строит (a ...), где ... - фактическое значение.

1 голос
/ 16 мая 2019

Сначала я бы обработал плоский случай (одноцепочечный, т.е. список баз).Перейдите к списку и подсчитайте каждую базу в хеш-таблицу:

(defun count-bases (dna)
  (let ((counts (make-hash-table)))
    (dolist (base dna counts)
      (incf (gethash base counts 0)))))

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

(defun count-bases (dna &optional (counts (make-hash-table)))
  (dolist (base-or-pair dna counts)
    (if (symbolp base-or-pair)
        (incf (gethash base-or-pair counts 0))
        (count-bases base-or-pair counts))))
...