C# 用C语言生成Excel列字母的最快函数#

C# 用C语言生成Excel列字母的最快函数#,c#,excel,performance,C#,Excel,Performance,最快的c#函数是什么?它接受和int并返回一个包含一个或多个字母的字符串,以便在Excel函数中使用?例如,1返回“A”,26返回“Z”,27返回“AA”,等等 这需要数万次调用,并且需要25%的时间来生成包含许多公式的大型电子表格 public string Letter(int intCol) { int intFirstLetter = ((intCol) / 676) + 64; int intSecondLetter = ((intCol % 676) / 26) +

最快的c#函数是什么?它接受和int并返回一个包含一个或多个字母的字符串,以便在Excel函数中使用?例如,1返回“A”,26返回“Z”,27返回“AA”,等等

这需要数万次调用,并且需要25%的时间来生成包含许多公式的大型电子表格

public string Letter(int intCol) {

    int intFirstLetter = ((intCol) / 676) + 64;
    int intSecondLetter = ((intCol % 676) / 26) + 64;
    int intThirdLetter = (intCol % 26) + 65;

    char FirstLetter = (intFirstLetter > 64) ? (char)intFirstLetter : ' ';
    char SecondLetter = (intSecondLetter > 64) ? (char)intSecondLetter : ' ';
    char ThirdLetter = (char)intThirdLetter;

    return string.Concat(FirstLetter, SecondLetter, ThirdLetter).Trim();
}

可以将所有值预生成为字符串数组。这将占用很少的内存,并且可以在第一次调用时进行计算。

绝对最快的方法是利用Excel电子表格中只有固定数量的列,因此您可以执行查找表。声明一个包含256个条目的常量字符串数组,并用从“a”到“IV”的字符串预填充它。然后您只需直接进行索引查找。

我可以告诉您,最快的函数不会是最漂亮的函数。这是:

private string[] map = new string[]
    { 
        "A", "B", "C", "D", "E" .............
    };

public string getColumn(int number)
{
    return map[number];
}
试试这个功能

// Returns name of column for specified 0-based index.
public static string GetColumnName(int index)
{
    var name = new char[3]; // Assumes 3-letter column name max.
    int rem = index;
    int div = 17576; // 26 ^ 3

    for (int i = 2; i >= 0; i++)
    {
        name[i] = alphabet[rem / div];
        rem %= div;
        div /= 26;
    }

    if (index >= 676)
        return new string(name, 3);
    else if (index >= 26)
        return new string(name, 2);
    else
        return new string(name, 1);
}
现在,为每个索引预生成每个列名并将它们存储在一个巨大的数组中不应该占用那么多内存,因此您不需要两次查找任何列的名称


如果我能想到任何进一步的优化,我会在以后添加它们,但我相信这个函数应该非常快,我怀疑如果你进行预生成,你甚至需要这种速度。

一旦你的函数运行了,让它将结果缓存到字典中。这样,它就不必再进行计算了


e、 g.Convert(27)将检查27是否映射/存储在字典中。如果没有,则进行计算并将“AA”与27对应存储在字典中。

根本不转换它。Excel可以在R1C1表示法中工作,就像在A1表示法中一样

因此(对使用VBA而不是C表示歉意):

可以很容易地写成:

Application.Worksheets("Sheet1").Cells(1, 2).Font.Bold = True
Range
属性采用A1表示法,而
Cells
属性采用(行号、列号)

要选择多个单元格:
范围(单元格(1,1),单元格(4,6))
(如果不使用活动工作表,NB需要某种对象限定符),而不是
范围(“A1:F4”)


属性可以采用字母(例如F)或数字(例如6)

您的第一个问题是在方法中声明了6个变量。如果一个methd要被调用数千次,只需将它们移动到类范围而不是函数范围,可能会立即将处理时间减少一半以上。

缓存确实会将10000000次随机调用的运行时间减少到其值的1/3:

    static Dictionary<int, string> LetterDict = new Dictionary<int, string>(676);
    public static string LetterWithCaching(int index)
    {
        int intCol = index - 1;
        if (LetterDict.ContainsKey(intCol)) return LetterDict[intCol];
        int intFirstLetter = ((intCol) / 676) + 64;
        int intSecondLetter = ((intCol % 676) / 26) + 64;
        int intThirdLetter = (intCol % 26) + 65;
        char FirstLetter = (intFirstLetter > 64) ? (char)intFirstLetter : ' ';
        char SecondLetter = (intSecondLetter > 64) ? (char)intSecondLetter : ' ';
        char ThirdLetter = (char)intThirdLetter;
        String s = string.Concat(FirstLetter, SecondLetter, ThirdLetter).Trim();
        LetterDict.Add(intCol, s);
        return s;
    }
static Dictionary letedict=新字典(676);
公共静态字符串LetterWithCaching(int索引)
{
int intCol=指数-1;
如果(LetterDict.ContainsKey(intCol))返回LetterDict[intCol];
intFirstLetter=((intCol)/676)+64;
intSecondLetter=((intCol%676)/26)+64;
intThirdLetter=(intCol%26)+65;
char FirstLetter=(intFirstLetter>64)?(char)intFirstLetter:“”;
char SecondLetter=(intSecondLetter>64)?(char)intSecondLetter:“”;
char ThirdLetter=(char)intThirdLetter;
String s=String.Concat(第一个字母、第二个字母、第三个字母).Trim();
添加字母DICT(intCol,s);
返回s;
}

我认为在最坏的情况下(命中每个值)缓存占用的空间不能超过250kb(17576个可能值*(sizeof(int)=4+sizeof(char)*3+字符串开销=2)

它是递归的。快速且正确:

class ToolSheet
{


    //Not the prettyest but surely the fastest :
    static string[] ColName = new string[676];


    public ToolSheet()
    {
        ColName[0] = "A";
        for (int index = 1; index < 676; ++index) Recurse(index, index);

    }

    private int Recurse(int i, int index)
    {
        if (i < 1) return 0;
        ColName[index] = ((char)(65 + i % 26)).ToString() + ColName[index];

        return Recurse(i / 26, index);
    }

    public string GetColName(int i)
    {
        return ColName[i - 1];
    }



}
类工具表
{
//不是最漂亮但肯定是最快的:
静态字符串[]ColName=新字符串[676];
公共工具表()
{
ColName[0]=“A”;
对于(int-index=1;index<676;++index)递归(index,index);
}
私有int递归(int i,int索引)
{
如果(i<1)返回0;
ColName[index]=((char)(65+i%26)).ToString()+ColName[index];
返回递归(i/26,索引);
}
公共字符串GetColName(int i)
{
返回ColName[i-1];
}
}

很抱歉有班次。已更正

class ToolSheet
{


    //Not the prettyest but surely the fastest :
    static string[] ColName = new string[676];


    public ToolSheet()
    {

        for (int index = 0; index < 676; ++index)
        {
            Recurse(index, index);
        }

    }

    private int Recurse(int i, int index)
    {
        if (i < 1)
        {
            if (index % 26 == 0 && index > 0) ColName[index] = ColName[index - 1].Substring(0, ColName[index - 1].Length - 1) + "Z";

            return 0;
        }


        ColName[index] = ((char)(64 + i % 26)).ToString() + ColName[index];


        return Recurse(i / 26, index);
    }

    public string GetColName(int i)
    {
        return ColName[i - 1];
    }



}
类工具表
{
//不是最漂亮但肯定是最快的:
静态字符串[]ColName=新字符串[676];
公共工具表()
{
对于(int-index=0;index<676;++index)
{
递归(索引,索引);
}
}
私有int递归(int i,int索引)
{
if(i<1)
{
如果(索引%26==0&&index>0)ColName[index]=ColName[index-1]。子字符串(0,ColName[index-1]。长度-1)+“Z”;
返回0;
}
ColName[index]=((char)(64+i%26)).ToString()+ColName[index];
返回递归(i/26,索引);
}
公共字符串GetColName(int i)
{
返回ColName[i-1];
}
}

我目前使用的是Excel 2007

public static string ExcelColumnFromNumber(int column)
        {
            string columnString = "";
            decimal columnNumber = column;
            while (columnNumber > 0)
            {
                decimal currentLetterNumber = (columnNumber - 1) % 26;
                char currentLetter = (char)(currentLetterNumber + 65);
                columnString = currentLetter + columnString;
                columnNumber = (columnNumber - (currentLetterNumber + 1)) / 26;
            }
            return columnString;
        }

正如在其他帖子中提到的,结果可以缓存。

@Neil N--代码不错,我认为第三个提交人应该有+64而不是+65?我说得对吗

public string Letter(int intCol) {

    int intFirstLetter = ((intCol) / 676) + 64;
    int intSecondLetter = ((intCol % 676) / 26) + 64;
    int intThirdLetter = (intCol % 26) + 65;  ' SHOULD BE + 64?

    char FirstLetter = (intFirstLetter > 64) ? (char)intFirstLetter : ' ';
    char SecondLetter = (intSecondLetter > 64) ? (char)intSecondLetter : ' ';
    char ThirdLetter = (char)intThirdLetter;

    return string.Concat(FirstLetter, SecondLetter, ThirdLetter).Trim();
}

这是用Java编写的,但基本上是一样的

下面是使用基于0的索引计算列标签(大写)的代码:

public static String findColChars(long index) {
    char[] ret = new char[64];
    for (int i = 0; i < ret.length; ++i) {
        int digit = ret.length - i - 1;
        long test = index - powerDown(i + 1);
        if (test < 0)
            break;
        ret[digit] = toChar(test / (long)(Math.pow(26, i)));
    }
    return new String(ret);
}

private static char toChar(long num) {
    return (char)((num % 26) + 65);
}
公共静态字符串findcochars(长索引){
char[]ret=新字符[64];
对于(int i=0;i
下面是从大写标签计算列的基于0的索引的代码:

public static long findColIndex(String col) {
    long index = 0;
    char[] chars = col.toCharArray();
    for (int i = 0; i < chars.length; ++i) {
        int cur = chars.length - i - 1;
        index += (chars[cur] - 65) * Math.pow(26, i);
    }
    return index + powerDown(chars.length);
}

private static long powerDown(int limit) {
    long acc = 0;
    while (limit > 1)
        acc += Math.pow(26, limit-- - 1);
    return acc;
}
公共静态long-findColIndex(字符串列){
长指数=0;
char[]chars=col.toCharArray();
对于(int i=0;ipublic static String findColChars(long index) {
    char[] ret = new char[64];
    for (int i = 0; i < ret.length; ++i) {
        int digit = ret.length - i - 1;
        long test = index - powerDown(i + 1);
        if (test < 0)
            break;
        ret[digit] = toChar(test / (long)(Math.pow(26, i)));
    }
    return new String(ret);
}

private static char toChar(long num) {
    return (char)((num % 26) + 65);
}
public static long findColIndex(String col) {
    long index = 0;
    char[] chars = col.toCharArray();
    for (int i = 0; i < chars.length; ++i) {
        int cur = chars.length - i - 1;
        index += (chars[cur] - 65) * Math.pow(26, i);
    }
    return index + powerDown(chars.length);
}

private static long powerDown(int limit) {
    long acc = 0;
    while (limit > 1)
        acc += Math.pow(26, limit-- - 1);
    return acc;
}
static IEnumerable<string> GetExcelStrings()
{
    string[] alphabet = { string.Empty, "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" };

    return from c1 in alphabet
           from c2 in alphabet
           from c3 in alphabet.Skip(1)                    // c3 is never empty
           where c1 == string.Empty || c2 != string.Empty // only allow c2 to be empty if c1 is also empty
           select c1 + c2 + c3;
}
static class ExcelHeaderHelper
{
    public static string[] GetHeaderLetters(uint max)
    {
        var result = new List<string>();
        int i = 0;
        var columnPrefix = new Queue<string>();
        string prefix = null;
        int prevRoundNo = 0;
        uint maxPrefix = max / 26;

        while (i < max)
        {
            int roundNo = i / 26;
            if (prevRoundNo < roundNo)
            {
                prefix = columnPrefix.Dequeue();
                prevRoundNo = roundNo;
            }
            string item = prefix + ((char)(65 + (i % 26))).ToString(CultureInfo.InvariantCulture);
            if (i <= maxPrefix)
            {
                columnPrefix.Enqueue(item);
            }
            result.Add(item);
            i++;
        }
        return result.ToArray();
    }
}
private string GenerateSequence(int num)
{
    string str = "";
    char achar;
    int mod;
    while (true)
    {
        mod = (num % 26) + 65;
        num = (int)(num / 26);
        achar = (char)mod;
        str = achar + str;
        if (num > 0) num--;
        else if (num == 0) break;
    }
    return str;
}
  var start = m_xlApp.Cells[nRow1_P, nCol1_P];
  var end = m_xlApp.Cells[nRow2_P, nCol2_P];
  // cast as Range to prevent binding errors
  m_arrRange = m_xlApp.get_Range(start as Range, end as Range);
  object[] values = (object[])m_arrRange.Value2;
public static string GetColumnName(int index)
{
    const string letters = "ZABCDEFGHIJKLMNOPQRSTUVWXY";

    int NextPos = (index / 26);
    int LastPos = (index % 26);
    if (LastPos == 0) NextPos--;

    if (index > 26)
        return GetColumnName(NextPos) + letters[LastPos];
    else
        return letters[LastPos] + "";
}
private String columnLetter(int column) {
    if (column <= 0) 
        return "";
    if (column <= 26){
        return (char) (column + 64) + "";
    }

    if (column%26 == 0){
        return columnLetter((column/26)-1) + columnLetter(26) ;        
    }

    return columnLetter(column/26) + columnLetter(column%26) ;        
}
=SUBSTITUTE(ADDRESS(ROW(),COLUMN(),4),ROW(),"")
def convert_num_to_column(column_num):
    result = ""
    quotient = column_num
    remainder = 0
    while (quotient >0):
        quotient = quotient -1
        remainder = quotient%26
        result = chr(int(remainder)+97)+result
        quotient = int(quotient/26)
    return result

print("--",convert_num_to_column(1).upper())