Битовая манипуляция для файла ДНК Convert

1

Я создаю программу в Scala, которая преобразует данные ДНК, хранящиеся в txt файлах, используя 8 бит на Char в файл, используя 2 бита на Char. Единственными символами, которые использует ДНК, являются T, C, A, G. Я хочу использовать 2 бита для каждого символа, где T = 00, C = 01, A = 10 и G = 11. Я хочу, чтобы это было настолько компактным, насколько возможно, без каких-либо потраченных впустую бит.

Прямо сейчас, я пишу 8 бит за Char вместо двух, которые я хочу использовать. Для метода outPut вы можете предложить любую манипуляцию с битами, которую я могу сделать, чтобы максимизировать пространство и использовать только два бита на символ?

  • 2
    Кто этот идиот, который продолжает опускать посты и убегает без комментариев?
  • 0
    Огорчает меня :(
Показать ещё 2 комментария
Теги:
bit-manipulation
bit-shift
stream

3 ответа

1
Лучший ответ

Невозможно вывести меньше байта за раз. Вам нужно будет построить 8-битный символ из двухбитных писем dna, прежде чем писать символ.

Я не знаю Scala или Java, но в сочетании вашего кода и чего-то более похожего на C он будет выглядеть следующим образом:

  def outPut(in: DataInputStream, out: DataOutputStream) {
    var result = getChars(in)

    int letter_count = 0       // whatever a plain old integer is called
    char byte = 0

    for(i <- 0 until result.length) {

      if (result(i) == "A") {
        byte = (byte << 2) | 2         // move byte over 2 bits and "or" in new bits
      }else if(result(i) == "T") {
        byte = (byte << 2) | 0         // the "| 0" part here actually does nothing
      }else if(result(i) == "C") {
        byte = (byte << 2) | 1
      }else {
        byte = (byte << 2) | 3
      }

      letter_count += 1

      if (letter_count == 4) {
        out.writeByte(byte)
        letter_count = 0
        byte = 0
      }

   }
  }

Обратите внимание также на user3580294.

Чтобы перейти в другое направление (от 2-битного кодирования до кодирования символов):

  def toLetter(x) {
    if (x == 0)
      return "T"
    else if (x == 1)
      return "C"
    else if (x == 2)
      return "A"
    else if (x == 3)
      return "G"
  }

  def outputLetters(in: DataInputStream, out: DataOutputStream) {
    var twobit = getChars(in)   // or however you read the file

    for(i <- 0 until twobit.length) {
      byte = twobit(i)
      out.writeByte(toLetter((byte >> 6) & 3))
      out.writeByte(toLetter((byte >> 4) & 3))
      out.writeByte(toLetter((byte >> 2) & 3))
      out.writeByte(toLetter( byte       & 3))
    }
  }

Это предполагает, что число букв равномерно делится на 4. Чтобы преодолеть это ограничение, вам нужно будет хранить дополнительную информацию в файле. Это может быть либо количество букв в последнем байте (от 1 до 4), либо общее количество букв, представленных в файле (из которых можно вычислить количество букв в последнем байте).

  • 0
    Спасибо. Так что, если я хочу перейти от 2bit к txt, есть идеи, как я могу это сделать?
  • 1
    @ user3335040 Я добавил еще один раздел в ответ. Вам придется исправить это, чтобы сделать это правильно Scala, но, надеюсь, вы поняли идею.
Показать ещё 1 комментарий
1

Что-то еще немного scala-ish. Группируйте базы в четыре (возможно, меньше для последней) и сопоставляйте каждую последовательность из четырех символов с соответствующими значениями.

def makeBits(base:Char):Int = {
        base match {
        case 'T' => 0
        case 'C' => 1
        case 'A' => 2
        case 'G' => 3
        case _ =>   -1 // some error here
    }
}  

def packBits(bases:String):Int = {
    var res:Int = 0
    for (bits <- bases) { res = (res << 2) + makeBits(bits)}
    res
}                           
val packed = "ATGCTTTADGCA".grouped(4).map(packBits)
1

Если вы можете записывать сразу несколько байтов одновременно, звучит как я, вам придется читать буквы в группах по 4 и использовать некоторое смещение бит, чтобы иметь возможность использовать все 8 бит на байт. Это может вызвать некоторые проблемы, хотя если количество букв не кратно 4, потому что у вас не будет способа отличить отступы от обычных букв...

(извините, я не знаю Scala, но этот алгоритм должен работать независимо от языка)

Так что-то вроде

// Store byte equivalents of ATCG in variables, or use an enum
// create new byte[4]
// Fill array with next 4 chars, ideally using something like Java InputStream.read(byte[] b) so you can read in groups
// create temp byte variable
for (int i = 3; i >= 0; i--) {
    switch(b) {
        case <byte equivalent of A>:
            temp += <binary equivalent of A> << 3 - i;
// Repeat for other letters
// Write out temp
  • 0
    Он также может хранить общее количество букв.
  • 0
    @ooga хорошая точка зрения, это также жизнеспособное решение

Ещё вопросы

Сообщество Overcoder
Наверх
Меню