Как я могу написать метод, который возвращает уникальную строку длиной 6 символов? - PullRequest
3 голосов
/ 30 ноября 2011

Если я делаю так, я получаю несколько дубликатов ...

private const string _chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123654987";

public string RandomString(int size)
{
    var random = new Random((int)DateTime.Now.Ticks);
    Thread.Sleep(random.Next(1, 3));

    var buffer = new char[size];

    for (int i = 0; i < size; i++)
    {
        buffer[i] = _chars[random.Next(_chars.Length)];
    }
    return new string(buffer);
}

Первый запрос 100000 должен быть уникальным, как я могу гарантировать его в принципе ... если возможно, я не хочу сохранятьсоставить список и запросить его ...

Ответы [ 6 ]

2 голосов
/ 30 ноября 2011
  • Определите наибольшее простое число, которое меньше 35 ^ 6 (количество возможных комбинаций).
  • Выберите случайное число, которое меньше этого, но больше единицы.
  • Take (ваш простой% (ваше случайное число * индекс итерации)).Это то, из чего вы строите свою строку.
  • Выразите результат в базе 35 и создайте свою строку.

Эти строки не будут перекрываться в течение 100 000 итераций, поскольку ваше случайное числоотносительно простое для большего числа.Кэширование не требуется.

Вы можете выполнить произвольное число итераций перед записью строк, чтобы получить больше места для результата.

0 голосов
/ 30 ноября 2011

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

public class Class1
{
    List<char> _chars = new List<char>() { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
        'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2','3','4', '5', '6', '7', '8', '9', '0' };
    private static int[] index = new int[6] {0, 0, 0, 0, 0, 0};
    private const int charMax = 35;

    public string UniqueString()
    {
        if (index[5] > charMax)
        {
            IncromentParent(5);
        }

        StringBuilder result = new StringBuilder();
        result.Append(_chars[index[0]]);
        result.Append(_chars[index[1]]);
        result.Append(_chars[index[2]]);
        result.Append(_chars[index[3]]);
        result.Append(_chars[index[4]]);
        result.Append(_chars[index[5]]);

        index[5]++;
        return result.ToString();
    }

    private void IncromentParent(int active)
    {
        if (active == 0)
            throw new Exception("out of numbers");

        int parent = active - 1;
        index[active] = 0;
        index[parent]++;
        if (index[parent] > charMax)
            IncromentParent(parent);
    } 
}

А вот проходной юнит-тест, но для его запуска требуется много времени ...

[TestMethod]
public void MyTestMethod()
{
    Class1 target = new Class1();
    List<string> results = new List<string>();

    for (int i = 0; i < 100000; i++)
    {            
        string result = target.UniqueString();

        if (!results.Contains(result))
            results.Add(result);
        else
            Assert.Fail(string.Format("The string '{0}' is already in the list", result));
    }
   Console.WriteLine(results.Count.ToString());
}
0 голосов
/ 30 ноября 2011

Вы можете использовать текущую метку времени (миллисекунды, микросекунды или наносекунды) (изменить ее или изменить порядок цифр, если вам нужно показать случайность) и заменить цифры в метке времени на AZ и 0-9 символовпо некоторым критериям.

В противном случае Если у вас нет какого-либо механизма кэширования для хранения ранее сгенерированных значений, я думаю, что вы не сможете получить случайные и УНИКАЛЬНЫЕ последовательности символов.

0 голосов
/ 30 ноября 2011

Если вы используете int для представления битовых позиций, вы можете легко это сделать.

int bits=0

...

while(bitCount(bits)!=6) // Write your own bitCount method--or there is probably one on the net
    bits++;

Теперь вы знаете, что у вас есть 6 бит в вашем int, поэтому конвертируйте их в строку

Например, с вашими данными:

"ABCDEFGHIJKLMNOPQRSTUVWXYZ123654987"

если вы считали и достигли 111111, (первое, которое вы нажмете), вы вернете «234567», следующим, я считаю, будет 1011111, который вернет «134567», затем «1101111», который вернется » 124567" . (Я могу ошибаться в последовательности, это просто с моей головы).

Он всегда будет уникальным, и итерации не так дороги, как вы думаете, хотя вы, возможно, будете немного умнее, чем просто итерации (вы можете пропустить большие группы, если вы поймете, что математически невозможно достичь следующий 6-битовый номер перед n приращениями, или вы можете просто придумать более простой алгоритм для генерации следующего целого числа с 6 1.

0 голосов
/ 30 ноября 2011

Не хранить список всех более ранних значений.Просто используйте счетчик.

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

0 голосов
/ 30 ноября 2011

Если ваша возможная длина случайной строки ограничена, было бы проще всего использовать GUID:

Необработанная реализация может быть:

    public string RandomString(int size)
    {
        return Guid.NewGuid()
            .ToString()
            .Replace("-","")
            .Substring(0, size);
    }

Если вам нужно больше, вы можете объединить несколькоСтроки GUID вместе.

...