我有以下排序数据:
AAA
AAA
TCG
TTT
TTT
TTT
我想计算每个字符串的出现次数:
AAA 2
TCG 1
TTT 3
我知道我可以使用uniq -c
来做到这一点,但在这里我需要对我所拥有的整体C ++代码进行额外的处理。
我坚持使用这个结构(根据'pgras'建议修改):
#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
using namespace std;
int main ( int arg_count, char *arg_vec[] ) {
if (arg_count !=2 ) {
cerr << "expected one argument" << endl;
return EXIT_FAILURE;
}
string line;
ifstream myfile (arg_vec[1]);
if (myfile.is_open())
{
int count;
string lastTag = "";
while (getline(myfile,line) )
{
stringstream ss(line);
string Tag;
ss >> Tag; // read first column
//cout << Tag << endl;
if (Tag != lastTag) {
lastTag = Tag;
count = 0;
}
else {
count++;
}
cout << lastTag << " " << count << endl;
}
cout << lastTag << " " << count << endl;
myfile.close();
}
else {cout << "Unable to open file";}
return 0;
}
它打印出错误的结果:
AAA 0
AAA 1
TCT 0
TTT 0
TTT 1
TTT 2
TTT 2
答案 0 :(得分:6)
如果您只想将其打印出来,那么您的算法就可以了。如果要将其传递给另一个函数,可以使用例如STL map。
map<string, int> dict;
while(getline(myfile,line)) {
string Tag;
stringstream ss(line);
ss >> Tag;
if (dict.count(Tag) == 0)
dict[Tag] = 1;
else
dict[Tag]++;
}
答案 1 :(得分:6)
当标签与lastTag不同时,您必须重置计数器,如果标签不同,则必须递增...当标签不同时,您可以使用它的相关计数值处理前一个标签(在重置计数之前)... < / p>
答案 2 :(得分:4)
使用类似的东西:
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#include <map>
#include <iterator>
std::ostream& operator << ( std::ostream& out, const std::pair< std::string, size_t >& rhs )
{
out << rhs.first << ", " << rhs.second;
return out;
}
int main()
{
std::ifstream inp( "mysorted_data.txt" );
std::string str;
std::map < std::string, size_t > words_count;
while ( inp >> str )
{
words_count[str]++;
}
std::copy(
words_count.begin(),
words_count.end(),
std::ostream_iterator< std::pair< std::string, size_t > >( std::cout, "\n" ) );
return 0;
}
答案 3 :(得分:4)
假设您的数据确实包含长度为3的DNA字符串(或更长的通用长度 N ,其中 N 非常小),您可以通过使用它来提高效率一个q-gram表,它是一个专门的哈希表,表大小为4 N 以及以下哈希函数:
// Disregard error codes.
int char2dna_lookup[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x0 – 0xF
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x10 – 0x1F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x20 – 0x2F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x30 – 0x3F
0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A – P
0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Q – 0x5F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x60 – 0x6F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x70 – 0x7F
}
unsigned int hash(string const& dna) {
unsigned int ret = 0;
for (unsigned int i = 0; i < dna.length(); ++i)
ret = ret * 4 + char2dna_lookup[dna[i]];
return ret;
}
您现在可以非常有效地索引阵列。
ifstream ifs("data.txt");
string line;
if (not ifs >> line)
exit(1);
unsigned* frequencies = new unsigned int[line.length()];
frequencies[hash(line)] = 1;
while (ifs >> line)
++frequencies[hash(line)];
// Print the frequencies …
delete[] frequencies;
或者,使用SeqAn等库来执行此类任务。
答案 4 :(得分:2)
我认为你所要做的就是替换这个
if (Tag != lastTag) {
lastTag = Tag;
count = 0;
}
else {
count++;
}
cout << lastTag << " " << count << endl;
用这个:
if (Tag != lastTag) {
if (lastTag != "") { // don't print initial empty tag
cout << lastTag << " " << count << endl;
}
lastTag = Tag;
count = 1; // count current
} else {
count++;
}
答案 5 :(得分:1)
你的代码在语法上略显破碎(ifstream
,...),但我认为整体算法是合理的。读取行,并在每次与前一行相同时递增计数器。可能有一些边界条件要考虑(如果输入只有一行怎么办?),但是你会在测试过程中发现它们。
答案 6 :(得分:1)
使用stringstream来获取标签似乎有点矫枉过正 - 我可能会使用string :: substr。除此之外,您认为您的代码有什么问题?你想改进什么?
编辑:接下来,我们将因呼吸而被投票......
答案 7 :(得分:1)
#include <map>
#include <string>
#include <algorithm>
#include <iterator>
#include <iostream>
class Counter
{ private: std::map<std::string,int>& m_count;
public: Counter(std::map<std::string,int>& data) :m_count(data){}
void operator()(std::string const& word)
{
m_count[word]++;
}};
class Printer
{ private: std::ostream& m_out;
public: Printer(std::ostream& out) :m_out(out) {}
void operator()(std::map<std::string,int>::value_type const& data)
{
m_out << data.first << " = " << data.second << "\n";
}};
int main()
{
std::map<std::string,int> count;
for_each(std::istream_iterator<std::string>(std::cin),
std::istream_iterator<std::string>(),
Counter(count)
);
for_each(count.begin(),count.end(),
Printer(std::cout)
);
}