组合..笛卡尔乘积

本文关键字:笛卡尔 组合 | 更新日期: 2023-09-27 18:02:14

我想使用给定字符的组合生成文件夹即具有字符组合的8个字符的文本:abcdefghijklmnopqrstuvxyz1234567890。对于8个字符的组合,有2821109907456种可能性。我想把这些按10000的范围分组。

我需要将这些文件夹放在相关的范围文件夹中,即。"aaaaaa 1-aaaaaa 9"是9个组合的范围,将在此范围文件夹中创建文件夹"aaaaaaa 3"。

我想使用c#代码,给我的方法一个文件夹名称,即"aaaaaaa3",并返回相关的文件夹范围,即应该保存的"aaaaaa 1-aaaaaa 9"。

问题:我需要c#代码来做这件事!

组合..笛卡尔乘积

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

类似这样的东西:

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

并使用总和来确定目标范围。只需将sum / 10000转换回36进制表示法即可。你完了。

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

/// <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];
}

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

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"。。。"00"。要缩短范围,请执行以下操作:

const string values = "abcdefghijklmnopqrstuvwxyz1234567890";

然后:

int index = values.IndexOf(fileName[7]);
if (index < 12) {
    start = "a";
    end = "l";
} else if (index < 24) ...