Combinations.... Cartesian Product? [closed]
I want to generate folders using combinations of given characters i.e. 8 character text with combination of characters: abcdefghijklmnopqrstuvwxyz1234567890. For the 8 characters combinations there are 2821109907456 possibilities. I want to group these by range of 10,000.
I need to put these folders in relevant range folders i.e. 'aaaaaaa1 - aaaaaaa9' is a range of 9 combinations and a folder 'aaaaaaa3' will be created in this range folder.
I want to use c# code, give my method a folder name i.e. 'aaaaaaa3' and be returned the relevant folder range i.e. 'aaaaaa1 - aaaaaaa9' where it should be saved.
Question: I need c# code to do this!
You are actually using 36-base notation (36 digits are used to represent numbers). So the easiest way to handle these filenames is to convert them to decimal notation and then just divide by 10000.
Something like this:
string alphabet = "0123456789abcdefghijklmnopqrstuvwxyz";
string fileName = "asdjg66";
long result = 0;
foreach (var c in fileName)
{
sum = sum * 36 + alphabet.IndexOf(c);
}
And use sum to determine the target range. Just convert sum / 10000
back to 36-base notation. And you are done.
From the beginning, it looks like we're going to need to compute ranges of alphanumeric sequences, which means converting them to numbers and back. An all-purpose base converter seems like the first logical step:
/// <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();
}
Then, you'll need the code to compute your ranges:
///<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));
}
}
Finally, tie the BaseConverter and NumericRangeFactory classes together to solve the problem with this sample static method:
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];
}
I haven't tested this, but I think the concept is solid.
string getRange(string fileName) {
string prefix = fileName.Substring(0, 7);
string start = "a";
string end = "0";
return prefix + start + " - " + prefix + end;
}
To make the range larger, most easily in powers of 36, make the prefix shorter and make the start and end repeat themselves a few times: (0, 6)
..."aa"
..."00"
. To make the range shorter, do something like this:
const string values = "abcdefghijklmnopqrstuvwxyz1234567890";
Then:
int index = values.IndexOf(fileName[7]);
if (index < 12) {
start = "a";
end = "l";
} else if (index < 24) ...
精彩评论