组合....笛卡尔积?

时间:2011-07-14 22:50:15

标签: c# range base

我想使用给定字符的组合生成文件夹 即带有字符组合的8个字符文本:abcdefghijklmnopqrstuvwxyz1234567890。 对于8个字符组合,有2821109907456种可能性。我希望按10,000的范围对这些进行分组。

我需要将这些文件夹放在相关的范围文件夹中,即 'aaaaaaa1 - aaaaaaa9'是9种组合的范围,将在此范围文件夹中创建文件夹'aaaaaaa'。

我想使用c#代码,给我的方法一个文件夹名称,即'aaaaaaa3',并返回相关的文件夹范围,即'aaaaaa1 - aaaaaaa9',它应该被保存。

问题:我需要c#代码来执行此操作!

3 个答案:

答案 0 :(得分:2)

您实际上使用的是36基数表示法(36位数字用于表示数字)。 因此,处理这些文件名的最简单方法是将它们转换为十进制表示法,然后除以10000.

这样的事情:

string alphabet = "0123456789abcdefghijklmnopqrstuvwxyz";
string fileName = "asdjg66";
long result = 0;
foreach (var c in fileName)
{
    sum = sum * 36 + alphabet.IndexOf(c);
}

并使用sum来确定目标范围。只需将sum / 10000转换回36基表示法。你完成了。

答案 1 :(得分:1)

string getRange(string fileName) {
    string prefix = fileName.Substring(0, 7);
    string start = "a";
    string end = "0";
    return prefix + start + " - " + prefix + end;
}

要使范围更大,最容易以36的幂,使前缀更短,并使开始和结束重复几次:(0, 6) ... "aa" ... {{ 1}}。要缩短范围,请执行以下操作:

"00"

然后:

const string values = "abcdefghijklmnopqrstuvwxyz1234567890";

答案 2 :(得分:1)

从一开始,看起来我们需要计算字母数字序列的范围,这意味着将它们转换为数字并返回。一个通用的基本转换器似乎是第一个合乎逻辑的步骤:

/// <summary>
/// Provides conversion between long integers and custom number bases.
/// </summary>
public class BaseConverter
{
    private string _characterSet;

    /// <summary>
    /// Creates a new BaseConverter.
    /// </summary>
    /// <param name="characterSet">The characters in the custom base, in  
    /// increasing order of value.</param>
    public BaseConverter(string characterSet = 
       "0123456789abcdefghijklmnopqrstuvwxyz")
    {
        _characterSet = characterSet;
    }

    /// <summary>
    /// Converts a number in the custom base system to a long.
    /// </summary>
    /// <param name="value">The custom base number to convert.</param>
    /// <returns>The long form of the custom base number.</returns>
    public long StringToLong(string value)
    {
        if (value == Convert.ToString(_characterSet[0])) return 0;
        long val = 0; 
        string text = value[0] == '-' ? value.Substring(1, 
           value.Length - 1) : value;

        for (int i = text.Length, power = 0; i != 0; i--, power++)
        {
            val += (long)Math.Round((_characterSet.IndexOf(text[i-1]) * 
               Math.Pow(_characterSet.Length, power)));
        }

        return value[0] == '-' ? -val : val;
    }

    /// <summary>
    /// Converts a long to the custom base system.
    /// </summary>
    /// <param name="value">The long to convert.</param>
    /// <returns>The custome base number version of the long.</returns>
    public string LongToString(long value)
    {
        if (value == 0) return Convert.ToString(_characterSet[0]);
        long number = value.Abs();
        int remainder;
        StringBuilder text = new StringBuilder((int)Math.Round(
           Math.Log(long.MaxValue, (double)_characterSet.Length)) + 
           value < 0 ? 1 : 0);

        while (number != 0)
        {
            remainder = (int)(number % _characterSet.Length);
            text.Insert(0, _characterSet[remainder]);
            number -= remainder;
            number /= _characterSet.Length;
        }

        if (value < 0) text.Insert(0, "-");
        return text.ToString();
    }

然后,您需要使用代码来计算范围:

///<summary>
///Computes numeric ranges using a BaseConverter.
///</summary>
public class NumericRangeFactory
{
   private long _min, _length;
   private BaseConverter _converter;

   //creates a new NumericRangeFactory
   //converter - the BaseConverter that defines the number system 
   //being used
   //min - the smallest value in an acceptable range
   //length - the number of values in a single range
   public NumericRangeFactory(BaseConverter converter, long min, 
      long length)
   {
      _converter = converter; _min = min; _length = length;
   }

   public NumericRangeFactory(BaseConverter converter, string min, 
      long length) : this(converter.StringToLong(min), length) {}

   //returns an array of long containing the min and max of the 
   //range that contains value
   public long[] GetLongRange(long value)
   {
      long min = _length * (value / _length); //todo: fix non-zero _min case
      return new long[] { min, min + length - 1 };    
   }

   public long[] GetLongRange(string value)
   {
      return GetLongRange(_converter.StringToLong(value));
   }

   //returns an array of string containing the min and max of 
   //the range that contains value
   public string[] GetStringRange(long value)
   {
      long[] range = GetLongRange(value);
      return new string[] {_converter.LongToString(range[0]),
         _converter.LongToString(range[1])};
   }

   public string[] GetStringRange(string value)
   {
      return GetStringRange(_converter.StringToLong(value));
   }
}

最后,将BaseConverter和NumericRangeFactory类绑在一起以解决此样本静态方法的问题:

public static string GetFolderRange(string folderName)
{
   BaseConverter converter = new BaseConverter();
   NumericRangeFactory rangeFactory = new NumericRangeFactory(converter, 
      "aaaaaaa0", 9);
   string[] range = rangeFactory.GetStringRange(folderName);
   return range[0] + "-" + range[1];
}

我没有对此进行过测试,但我认为这个概念是可靠的。