使用55K行和不同的列对文件进行排序

时间:2010-03-29 22:08:48

标签: c++ sorting arrays dimensional

我想找到一个使用C ++的编程解决方案。

我有一个每个27MB大小的900个文件。 (只是为了告知这个问题)。

每个文件都有55K行和不同的列。但标题表示列

我想按照w.r.t的顺序将行排序为列值。

我为此编写了排序算法(绝对是我的新手尝试,你可能会说)。 该算法适用于少数数字,但对于较大的数字则失败。

以下是相同的代码: 我定义在主代码中使用的基本函数:

int getNumberOfColumns(const string& aline)
{
 int ncols=0;
 istringstream ss(aline);
 string s1;
 while(ss>>s1) ncols++;
 return ncols;
}

vector<string> getWordsFromSentence(const string& aline)
{
 vector<string>words;
 istringstream ss(aline);
 string tstr;
 while(ss>>tstr) words.push_back(tstr);
 return words;
}

bool findColumnName(vector<string> vs, const string& colName)
{
 vector<string>::iterator it = find(vs.begin(), vs.end(), colName);
 if ( it != vs.end()) 
 return true;
 else return false;
}

int getIndexForColumnName(vector<string> vs, const string& colName)
{
 if ( !findColumnName(vs,colName) ) return -1;
 else {
  vector<string>::iterator it = find(vs.begin(), vs.end(), colName);
 return it - vs.begin();
 }
}

////////// I like the Recurssive functions - I tried to create a recursive function
///here. This worked for small values , say 20 rows. But for 55K - core dumps
void sort2D(vector<string>vn, vector<string> &srt, int columnIndex)
{
  vector<double> pVals;
 for ( int i = 0; i < vn.size(); i++) {
  vector<string>meancols = getWordsFromSentence(vn[i]);
  pVals.push_back(stringToDouble(meancols[columnIndex]));
 }

        srt.push_back(vn[max_element(pVals.begin(), pVals.end())-pVals.begin()]);
        if (vn.size() > 1 ) {
        vn.erase(vn.begin()+(max_element(pVals.begin(), pVals.end())-pVals.begin()) );
        vector<string> vn2 = vn;
 //cout<<srt[srt.size() -1 ]<<endl;
        sort2D(vn2 , srt, columnIndex);
        }
}

现在主要代码:

 for ( int i = 0; i < TissueNames.size() -1; i++)
 {
  for ( int j = i+1; j < TissueNames.size(); j++)
  {
   //string fname = path+"/gse7307_Female_rma"+TissueNames[i]+"_"+TissueNames[j]+".txt";
   //string fname2 = sortpath2+"/gse7307_Female_rma"+TissueNames[i]+"_"+TissueNames[j]+"Sorted.txt";
   string fname = path+"/gse7307_Male_rma"+TissueNames[i]+"_"+TissueNames[j]+".txt";
   string fname2 = sortpath2+"/gse7307_Male_rma"+TissueNames[i]+"_"+TissueNames[j]+"4Columns.txt";
   vector<string>AllLinesInFile;
   BioInputStream fin(fname);
   string aline;
   getline(fin,aline);
   replace (aline.begin(), aline.end(), '"',' ');
   string headerline = aline;
   vector<string> header = getWordsFromSentence(aline);

   int pindex = getIndexForColumnName(header,"p-raw");
   int xcindex = getIndexForColumnName(header,"xC");
   int xeindex = getIndexForColumnName(header,"xE");
   int prbindex = getIndexForColumnName(header,"X");

   string newheaderline = "X\txC\txE\tp-raw";
   BioOutputStream fsrt(fname2);
   fsrt<<newheaderline<<endl;

   int newpindex=3;
   while ( getline(fin, aline) ){

   replace (aline.begin(), aline.end(), '"',' ');
   istringstream ss2(aline);
   string tstr;
   ss2>>tstr;
   tstr = ss2.str().substr(tstr.length()+1);
   vector<string> words = getWordsFromSentence(tstr);
   string values = words[prbindex]+"\t"+words[xcindex]+"\t"+words[xeindex]+"\t"+words[pindex];
    AllLinesInFile.push_back(values);
   }

   vector<string>SortedLines; 
   sort2D(AllLinesInFile, SortedLines,newpindex);

   for ( int si = 0; si < SortedLines.size(); si++)
    fsrt<<SortedLines[si]<<endl;
   cout<<"["<<i<<","<<j<<"] = "<<SortedLines.size()<<endl;
  }
 }

有人可以建议我这样做的更好方法吗? 为什么没有更大的价值观。 ?

此查询感兴趣的主要功能是Sort2D功能。

感谢您的时间和耐心。

普拉萨德。

4 个答案:

答案 0 :(得分:2)

我不确定为什么你的代码会崩溃,但在这种情况下递归只会降低代码的可读性。我怀疑这是一个堆栈溢出,因为你没有在每次调用中使用太多的堆栈空间。

C ++已经有std::sort,为什么不使用它呢?你可以这样做:

// functor to compare 2 strings
class CompareStringByValue : public std::binary_function<string, string, bool>
{
public:
    CompareStringByValue(int columnIndex) : idx_(columnIndex) {}
    bool operator()(const string& s1, const string& s2) const
    {
        double val1 = stringToDouble(getWordsFromSentence(s1)[idx_]);
        double val2 = stringToDouble(getWordsFromSentence(s2)[idx_]);
        return val1 < val2;
    }
private:
    int idx_;
};

然后对你要调用的行进行排序

std::sort(vn.begin(), vn.end(), CompareByStringValue(columnIndex));

现在,有一个问题。这会很慢,因为在同一个字符串上多次调用stringToDoublegetWordsFromSentence。您可能希望生成一个单独的向量,该向量已预先计算每个字符串的值,然后让CompareByStringValue仅将该向量用作查找表。

另一种方法是将字符串插入std::multimap<double, std::string>。只需将条目插入(value, str),然后逐行读取。这更简单但更慢(尽管具有相同的大O复杂度)。

编辑:清除了一些不正确的代码并从binary_function派生。

答案 1 :(得分:1)

您可以尝试一种不涉及递归的方法。如果您的程序使用具有较大值的Sort2D函数崩溃,那么您可能会溢出堆栈(使用大量函数调用的递归的危险)。尝试另一种排序方法,可能使用循环。

答案 2 :(得分:0)

问题是您的代码少于您为工作选择的工具。这纯粹是一个文本处理问题,所以选择一个好的工具。在Unix的情况下,最好的工具是Bash和GNU coreutils。在Windows上,您可以使用PowerShell,Python或Ruby。 Python和Ruby也适用于任何Unix风格的机器,但大多数Unix机器都安装了Bash和coreutils。

$FILES保存要处理的文件列表,由空格分隔。这是Bash的代码:

for FILE in $FILES; do
  echo "Processing file $FILE ..."
  tail --lines=+1 $FILE |sort >$FILE.tmp
  mv $FILE.tmp $FILE
done

答案 3 :(得分:0)

sort2D崩溃,因为你继续分配一个字符串数组进行排序,然后按值传递它,实际上是使用O(2 * N ^ 2)内存。如果您真的想要保留递归功能,只需通过引用传递vn,而不必担心vn2。如果您不想修改原始vn,请将sort2D的正文移至另一个函数(例如sort2Drecursive)并从sort2D调用该函数。

你可能想要另外看一下sort2D,因为你正在为O(N + N * log(N))做一些O(N ^ 2)工作。