我是Java的初学者,我想知道如何从.txt文件中的一串DNA中读取特定元素。例如,假设文本文件包含以下内容:
G A A A G G G A A G A T A G T
我想知道如何最好地遍历字符串并按顺序查找特定的字符集。一个例子是找到多少次" TAG"出现在读入字符串中。这就是我到目前为止所拥有的:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class DNA {
public static void main(String args[]) {
String fileName = args[0];
Scanner s = null;
try {
s = new Scanner(new File(fileName));
} catch (FileNotFoundException e) {
e.printStackTrace();
s.close();
}
String dna = "";
while(s.hasNext()) {
dna += s.next().trim();
}
s.close();
String subsequence = "TAG";
int count = 0;
for (int i = 0; i < dna.length(); i++){
if (dna.charAt(i) == subsequence.charAt(i)){
count = count + 1;
i++;
}
}
while (dna.charAt() == subsequence.charAt()){
count++;
}
System.out.println(subsequence + " appears " + count + " times");
}
}
它太乱了,我试图使用我在其他例子中经过多个小时的搜索后发现的逻辑。请让我知道如何更有效,并使用更好的逻辑!我喜欢学习这些东西,并愿意接受任何更正。
答案 0 :(得分:0)
您可以使用子字符串来完成此操作。由于TAG是3个字符,您可以从i - &gt;中获取子字符串。 i + 3循环的每次迭代并与“TAG”进行比较。
在A G A A A A G G G A A A G A T A G T的例子中,循环将迭代如下:
“AGA” .equals( “TAG”)
“GAA” .equals( “TAG”)
“AAA” .equals( “TAG”)
“AAA” .equals( “TAG”)
“AAG” .equals( “TAG”)
“AGG” .equals( “TAG”)
“GGG” .equals( “TAG”)
等。
如果您不熟悉,子字符串上有信息here。如果这不完全有意义,我可以尝试解释更多并提供psuedocode
答案 1 :(得分:0)
在循环中,您计算每个字符的出现次数而不是子序列的出现次数。您可以做的是比较您的子序列与:
Substring of dnb of length 3 characters starting from i
我说3个字符,因为你的子序列是"TAG"
。
您可以通过将子序列长度存储在变量中来概括。
您还需要检查i + subsequence length
是否在字符串的边界内。
否则,您将获得IndexOutOfBoundsException
代码:
//current index i + sublen cannot exceed dna length
//portion of dna starting from i and going sublen characters has to equal subsequence
int countSubstring(String subsequence, String dna) {
int count = 0;
int sublen = subsequence.length(); // lenght of the subsequence
for (int i = 0; i < dna.length(); i++){
if ((i + sublen) < dna.length() &&
dna.substring(i, i + sublen).equals(subsequence)){
count = count + 1;
}
}
return count;
}
尝试使用Rossetta Code来寻找一些示例方法:
&#34;删除并计算差异&#34;方法:
public int countSubstring(String subStr, String str){
return (str.length() - str.replace(subStr, "").length()) / subStr.length();
}
&#34>分裂和计数&#34;方法:
public int countSubstring(String subStr, String str){
// the result of split() will contain one more element than the delimiter
// the "-1" second argument makes it not discard trailing empty strings
return str.split(Pattern.quote(subStr), -1).length - 1;
}
手动循环(类似于我在顶部展示的代码):
public int countSubstring(String subStr, String str){
int count = 0;
for (int loc = str.indexOf(subStr); loc != -1;
loc = str.indexOf(subStr, loc + subStr.length()))
count++;
return count;
}
对于您的特定程序,只要从文件中读取,您应该将所有读取操作放在try
块中,然后在finally
块中关闭资源。如果您想了解有关Java I / O的更多信息,请转到here,然后转到finally
块,转到here。有很多方法可以从文件中读取信息,我只是向您展示了一个需要对代码进行最少更改的方法。
您可以在代码中添加任意countSubstring
方法,例如:
public static void main(String args[]) {
String fileName = args[0];
Scanner s = null;
String subsequence = "TAG";
String dna = "";
int count = 0;
try {
s = new Scanner(new File(fileName));
while(s.hasNext()) {
dna += s.next().trim();
}
count = countSubstring(subsequence, dna); // any of the above methods
System.out.println(subsequence + " appears " + count + " times");
} catch (FileNotFoundException e) {
e.printStackTrace();
// s.close(); Don't put s.close() here, use finally
} finally {
if(s != null) {
s.close();
}
}
}
答案 2 :(得分:0)
你有dna String和subsequence String,然后
int count = (dna.length() - line.replace(subsequence, "").length())/subsequence.length();
答案 3 :(得分:0)
要在不同的字符模式上搜索字符串&#34; Pattern&#34;和#34;匹配&#34;课程是一个很好的解决方案。
以下是一些有助于解决问题的代码:
int count = 0;
String line = "T A G A A A A G G G A A A G A T A G T A G";
Pattern pattern = Pattern.compile("T A G");
Matcher matcher = pattern.matcher(line);
while (matcher.find())
count++;
System.out.println(count);
由Pattern.compile(String s)编译的表达式称为Regex。在这种情况下,它只是寻找&#34; T A G&#34;在字符串中。使用while循环可以计算出现的次数。
如果你想做更复杂的事情,请查看有关正则表达式的更多信息。
答案 4 :(得分:0)
不要只计算TAG的实例,而是尝试一次计算多个密码子。
public static final void main( String[] args )
{
String input = "TACACTAGATCGCACTGCTAGTATC";
if (args.length > 0) {
input = args[0].trim();
}
System.out.println(input);
HashMap<Character, Node> searchPatterns = createCodons();
findCounts(input, searchPatterns);
printCounts(searchPatterns);
}
此解决方案使用树来存储我们感兴趣的字符序列。树中从根到叶的每条路径表示可能的序列。我们将创造四棵树;密码子以T开头,带有A,带有C,带有G.我们将这些树存储在HashMap中,以便通过它们的起始字符进行检索。
/**
Create a set of sequences we are interesting in finding (subset of
possible codons). We could specify any pattern we want here.
*/
public static final HashMap<Character, Node> createCodons()
{
HashMap<Character, Node> codons = new HashMap<Character,Node>();
Node sequencesOfT = new Node('T'); // T
Node nodeA = sequencesOfT.addChild('A'); // /
nodeA.addChild('C'); // A
nodeA.addChild('G'); // / \
codons.put('T', sequencesOfT); // C G
Node sequencesOfA = new Node('A'); // A
Node nodeT = sequencesOfA.addChild('T'); // /
nodeT.addChild('C'); // T
nodeT.addChild('G');; // / \
codons.put('A', sequencesOfA); // C G
Node sequencesOfC = new Node('C'); // C
Node nodeG = sequencesOfC.addChild('G'); // /
nodeG.addChild('T'); // G
nodeG.addChild('A'); // / \
codons.put('C', sequencesOfC); // T A
Node sequencesOfG = new Node('G'); // G
Node nodeC = sequencesOfG.addChild('C'); // /
nodeC.addChild('T'); // C
nodeC.addChild('A'); // / \
codons.put('G', sequencesOfG); // T A
return codons;
}
这是我们的Node类的样子。
public class Node
{
public char data; // the name of the node; A,C,G,T
public int count = 0; // we'll keep a count of occurrences here
public Node parent = null;
public List<Node> children;
public Node( char data )
{
this.data = data;
children = new ArrayList<Node>();
}
public Node addChild( char data )
{
Node node = new Node(data);
node.parent = this;
return (children.add(node) ? node : null);
}
public Node getChild( int index )
{
return children.get(index);
}
public int hasChild( char data )
{
int index = -1;
int numChildren = children.size();
for (int i=0; i<numChildren; i++)
{
Node child = children.get(i);
if (child.data == data)
{
index = i;
break;
}
}
return index;
}
}
要计算出现的次数,我们将迭代输入的每个字符,并且每次迭代检索我们感兴趣的树(A,G,C或T)。然后我们尝试沿着树走下去(从root to leaf)使用输入的后续字符 - 当我们无法在节点的子节点列表中找到输入的下一个字符时,我们停止遍历。此时,我们在该节点上递增计数,以指示在该节点处找到的字符序列。
public static final void findCounts(String input, HashMap<Character,Node> sequences)
{
int n = input.length();
for (int i=0; i<n; i++)
{
char root = input.charAt(i);
Node sequence = sequences.get(root);
int j = -1;
int c = 1;
while (((i+c) < n) &&
((j = sequence.hasChild(input.charAt(i+c))) != -1))
{
sequence = sequence.getChild(j);
c++;
}
sequence.count++;
}
}
要打印结果,我们将从树根到叶子遍历每个树,在遇到它们时打印节点,并在到达叶子时打印计数。
public static final void printCounts( HashMap<Character,Node> sequences )
{
for (Node sequence : sequences.values())
{
printCounts(sequence, "");
}
}
public static final void printCounts( Node sequence, String output )
{
output = output + sequence.data;
if (sequence.children.isEmpty())
{
System.out.println(output + ": " + sequence.count);
return;
}
for (int i=0; i<sequence.children.size(); i++)
{
printCounts( sequence.children.get(i), output );
}
}
以下是一些示例输出:
TAGAAAAGGGAAAGATAGT
TAC: 0
TAG: 2
GCT: 0
GCA: 0
ATC: 0
ATG: 0
CGT: 0
CGA: 0
TAGCGTATC
TAC: 0
TAG: 1
GCT: 0
GCA: 0
ATC: 1
ATG: 0
CGT: 1
CGA: 0
从这里我们可以轻松扩展解决方案,以保留每个序列的位置列表,或记录有关输入的其他信息。这种实现有点粗糙,但希望这可以为您解决问题的其他方式提供一些见解。