组合..笛卡尔乘积
本文关键字:笛卡尔 组合 | 更新日期: 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) ...