【问题标题】:Generate (not so)random string with particular string occurences生成(不是这样)具有特定字符串出现的随机字符串
【发布时间】:2015-07-01 11:38:53
【问题描述】:

我有一个要求,我有字母“ACGT”,我需要创建一个大约 20,000 个字符的字符串。此字符串应包含 100 多次出现的模式“CCGT”。大多数情况下,生成的字符串包含大约 20-30 个实例。

    int N = 20000;
    std::string alphabet("ACGT");
    std::string str;
    str.reserve(N);
    for (int index = 0; index < N; index++)
    {
        str += alphabet[rand() % (alphabet.length())];
    }

如何调整代码以使模式更频繁地出现?

编辑 - 有没有办法改变字母表,即 - 'A'、'C'、'G'、'T'、'CCGT' 作为字母表中的字符?

谢谢。

【问题讨论】:

  • N / 4 / 100迭代,插入特殊序列,同时跳过index中的四个字符?
  • 问题似乎是rand,我建议看these alternatives
  • @Jefffrey 我认为 OP 想要权衡随机性以比另一个更频繁地生成一个特殊序列,这与重复完全不同,所以我投票重新打开。
  • 你怎么能有多个子串的概率?我想你的意思是“发生”。如果必须至少有100个,它怎么可能是随机的
  • @Skizz 是的,对不起,我就是这个意思

标签: c++ string random


【解决方案1】:

生成一个包含 100 x 0 和 490 个 1、2、3 和 4 的整数数组 [000000....111111....2222 等] 产生了近 20,000 个条目。

然后随机洗牌(std::random_shuffle)

然后写一个字符串,其中每个 0 转换为 'CCGT',每个 1 转换为 'A',每个 2 .... 等等

我认为这可以满足您的需求,通过调整原始整数数组,您也可以更改输出中“A”字符的数量。

编辑:如果这不够随机,请在开始时执行 100 个 0,然后在其余部分随机执行 1-4。

【讨论】:

  • 我认为应该是 400 个 1s - 4s,目前它加起来最多 2360 个字符。
  • 好吧,总共有 100 个 0 和 (20,000 - (100 * 4)) - 我假设幻数也不会出现在真实代码中
  • 这几乎是 OP 的原始建议——它只是通过将“CCGT”视为单个字符直到它结束来简化问题。您可以轻松生成包含 100 个“X”字符的字符串,然后替换,尽管我认为改组是获得 100 个字符的最简单方法。
【解决方案2】:

我能想到的满足“100+”标准的唯一解决方案是:

create 20000 character string
number of instances (call it n) = 100 + some random value
for (i = 0 ; i < n ; ++i)
{
   pick random start position
   write CCGT
}

当然,您需要确保被覆盖的字符不是“CCGT”的一部分。

【讨论】:

    【解决方案3】:

    我的第一个想法是生成一个包含 100 个索引的列表,您肯定会在其中插入特殊字符串。然后在生成随机字符串时,在到达每个索引时插入特殊字符串。

    我错过了检查间隔是否适当间隔(不能在另一个间隔的 4 以内)以及按升序对它们进行排序——这两者都是必要的。

    int N = 20000;
    std::string alphabet("ACGT");
    int intervals[100];
    for (int index = 0; index < 100; index)
    {
        intervals[index] = rand() % 2000;
        // Do some sort of check to make sure each element of intervals is not
        // within 4 of another element and that no elements are repeated
    }
    // Sort the intervals array in ascending order
    int current_interval_index = 0;
    std::string str;
    str.reserve(N);
    for (int index = 0; index < N; index++)
    {
        if (index == intervals[current_interval_index])
        {
            str += alphabet;
            current_interval_index++;
            index += 3;
        }
        else
        {
            str += alphabet[rand() % (alphabet.length())];
        }
    }
    

    【讨论】:

      【解决方案4】:

      我想出的解决方案使用 std::vector 来包含所有 4 个字符的随机集,包括 100 个特殊序列。然后我打乱该向量以在整个字符串中随机分配 100 个特殊序列。

      为了分配字母,即使我创建了一个名为 weighted 的替代 alphabet 字符串,根据 100 个特殊序列中已经包含的内容,该字符串包含相对丰富的 alphabet 字符。

      int main()
      {
          std::srand(std::time(0));
      
          using std::size_t;
      
          const size_t N = 20000;
      
          std::string alphabet("ACGT");
      
          // stuff the ballot
          std::vector<std::string> v(100, "CCGT");
      
          // build a properly weighted alphabet string
          // to give each letter equal chance of appearing
          // in the final string
      
          std::string weighted;
      
          // This could be scaled down to make the weighted string much smaller
      
          for(size_t i = 0; i < (N - 200) / 4; ++i) // already have 200 Cs
              weighted += "C";
      
          for(size_t i = 0; i < (N - 100) / 4; ++i) // already have 100 Ns & Gs
              weighted += "GT";
      
          for(size_t i = 0; i < N / 4; ++i)
              weighted += "A";
      
          size_t remaining = N - (v.size() * 4);
      
          // add the remaining characters to the weighted string
          std::string s;
          for(size_t i = 0; i < remaining; ++i)
              s += weighted[std::rand() % weighted.size()];
      
          // add the random "4 char" sequences to the vector so
          // we can randomly distribute the pre-loaded special "4 char"
          // sequence among them.
          for(std::size_t i = 0; i < s.size(); i += 4)
              v.push_back(s.substr(i, 4));
      
          // distribute the "4 char" sequences randomly
          std::random_shuffle(v.begin(), v.end());
      
          // rebuild string s from vector
          s.clear();
          for(auto&& seq: v)
              s += seq;
      
          std::cout << s.size() << '\n'; // should be N
      }
      

      【讨论】:

        【解决方案5】:

        我喜欢@Andy Newman 的回答,并认为这可能是最好的方法 - 下面的代码是他们建议的可编译示例。

        #include <string>
        #include <algorithm>
        #include <iostream>
        
        int main()
        {
            srand(time(0));
            int N = 20000;
            std::string alphabet("ACGT");
            std::string str;
            str.reserve(N);
            int int_array[19700];
            // Populate int array
            for (int index = 0; index < 19700; index++)
                {
                if (index < 100)
                {
                    int_array[index] = 0;
                }
                else
                {
                    int_array[index] = (rand() % 4) + 1;
                }
            }
            // Want the array in a random order
            std::random_shuffle(&int_array[0], &int_array[19700]);
            // Now populate string from the int array
            for (int index = 0; index < 19700; index++)
            {
                switch(int_array[index])
                {
                    case 0:
                        str += alphabet;
                        break;
                    case 1:
                        str += 'A';
                        break;
                    case 2:
                        str += 'C';
                        break;
                    case 3:
                        str += 'G';
                        break;
                    case 4:
                        str += 'T';
                        break;
                    default:
                        break;
                }
            }
            // Print out to check what it looks like
            std::cout << str << std::endl;
        }
        

        【讨论】:

          【解决方案6】:

          您应该将N 放大。

          我冒昧地说,'创建一个 大约 20,000 个字符的字符串';但不止于此。

          如果您只在 20000 个字符的字符串中找到大约 20-30 个实例,那么就出了问题。一个大概的估计是说有 20000 个字符位置要测试,并且在每个位置都会有一个来自四个字母的字母表中的四个字母的字符串,它有 1/256 的机会是一个特定的字符串。平均值应该是(大约;因为我过于简单化了)20000/256,即 78 次点击。

          可能是您的字符串没有正确随机化(可能是由于使用了取模习语),或者您可能只测试每四个字符位置 - 就好像字符串是不重叠的列表四个字母的单词。

          如果您可以将平均命中率恢复到 78,那么您只需按比例增加 N,就可以进一步达到 100 的要求。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-03-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-02-19
            • 2017-08-01
            相关资源
            最近更新 更多