Самая быстрая функция для генерации букв столбца Excel в C#

Используя ответ stackoverflow.com/q/6877486/4139335 , который был предложен @MichaelWarner. Я заметил, что мне не хватало 301 в моем RedirectMatch

Это сработало: RedirectMatch 301 ^/portalweb/$ https://www.mywebsite.com.br Я не знаю, почему 301 добились цели, если кто-то объяснит мне, я бы будь рад.

35
задан Lance Roberts 7 May 2009 в 22:08
поделиться

11 ответов

Попробуйте эту функцию .

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

Теперь не нужно , что много памяти для предварительного создания имени каждого столбца для каждого индекса и сохранения их в одном огромном массиве, поэтому вам не нужно искать имя для любого столбца дважды.

Если я смогу придумать какие-либо дальнейшие оптимизации, я добавлю их позже, но я считаю, что эта функция должна быть довольно быстрой, и я сомневаюсь, что вам даже понадобится такая скорость, если вы сделаете предварительную поколения.

2
ответ дан 27 November 2019 в 06:33
поделиться

Абсолютный БЫСТРЫЙ, будет заглавными буквами, что в электронной таблице Excel только фиксированное количество столбцов, поэтому вы должны сделать таблицу поиска. Объявите постоянный строковый массив из 256 записей и предварительно заполните его строками от «A» до «IV». Затем вы просто выполняете прямой поиск по индексу.

2
ответ дан 27 November 2019 в 06:33
поделиться

После запуска функции позвольте ей кэшировать результаты в словарь. Так что ему не придется снова выполнять вычисления.

например, Convert (27) проверит, отображается ли / сохраняется ли 27 в словаре. В противном случае выполните вычисление и сохраните «AA» против 27 в словаре.

2
ответ дан 27 November 2019 в 06:33
поделиться

Вы можете предварительно сгенерировать все значения в массив строк. Это займет очень мало памяти и может быть вычислено при первом вызове.

4
ответ дан 27 November 2019 в 06:33
поделиться

Не конвертируйте его вообще. Excel может работать в нотации R1C1 так же, как и в нотации A1.

Итак (извинения за использование VBA, а не C #):

Application.Worksheets("Sheet1").Range("B1").Font.Bold = True

можно написать так же легко, как:

Application.Worksheets("Sheet1").Cells(1, 2).Font.Bold = True

Диапазон свойство принимает обозначение A1, тогда как свойство Cells принимает (номер строки, номер столбца).

Чтобы выбрать несколько ячеек: Range (Cells (1, 1), Cells (4, 6)) (NB понадобится какой-то квалификатор объекта, если не используется активная рабочая таблица), а не Range ("A1: F4")

Свойство Columns может принимать либо букву ( например, F) или число (например, 6)

14
ответ дан 27 November 2019 в 06:33
поделиться

Я могу сказать вам, что самая быстрая функция не будет самой красивой функцией. Вот он:

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

public string getColumn(int number)
{
    return map[number];
}
19
ответ дан 27 November 2019 в 06:33
поделиться

Ваша первая проблема заключается в том, что вы объявляете в методе 6 переменных. Если метод будет вызываться тысячи раз, простое перемещение их в область видимости класса вместо области действия функции, вероятно, сразу же сократит время обработки более чем наполовину.

2
ответ дан 27 November 2019 в 06:33
поделиться

Кэширование действительно сокращает время выполнения 10 000 000 случайных вызовов до 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;
    }

Я думаю, что кеширование в худшем случае (попадание каждого значения) не могло занять больше чем 250 КБ (17576 возможных значений * (sizeof (int) = 4 + sizeof (char) * 3 + string overhead = 2)

0
ответ дан 27 November 2019 в 06:33
поделиться

Это рекурсивно. Быстро и правильно:

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



}
0
ответ дан 27 November 2019 в 06:33
поделиться

извините, произошла смена. исправлено.

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



}
0
ответ дан 27 November 2019 в 06:33
поделиться

В настоящее время я использую это с 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;
        }

и

public static int NumberFromExcelColumn(string column)
        {
            int retVal = 0;
            string col = column.ToUpper();
            for (int iChar = col.Length - 1; iChar >= 0; iChar--)
            {
                char colPiece = col[iChar];
                int colNum = colPiece - 64;
                retVal = retVal + colNum * (int)Math.Pow(26, col.Length - (iChar + 1));
            }
            return retVal;
        }

Как упоминалось в других сообщениях, результаты можно кэшировать.

49
ответ дан 27 November 2019 в 06:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: