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

Какая самая быстрая функция 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();
}

Ответы [ 21 ]

48 голосов
/ 06 августа 2009

Я сейчас использую это, с 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;
        }

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

19 голосов
/ 08 мая 2009

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

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

public string getColumn(int number)
{
    return map[number];
}
14 голосов
/ 08 мая 2009

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

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

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

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

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

Свойство Range принимает нотацию A1, а свойство Cells (номер строки, номер столбца).

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

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

5 голосов
/ 07 февраля 2013

Вот моя версия: Это не имеет никаких ограничений как 2-х или 3-х буквенное. Просто введите требуемое число (начиная с 0). Будет возвращен заголовок столбца Excel в виде последовательности алфавита для переданного номера:

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

Я не проверял это на производительность, если кто-то может это сделать, то отлично подойдет для других. (Извините за то, что ленивый):)

ура!

4 голосов
/ 08 мая 2009

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

2 голосов
/ 18 ноября 2011

Это написано на 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);
}

Вот код для вычисления индекса на основе 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;
}
2 голосов
/ 08 мая 2009

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

// 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 голосов
/ 08 мая 2009

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

2 голосов
/ 08 мая 2009

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

2 голосов
/ 08 мая 2009

Как только ваша функция запустится, пусть она кеширует результаты в словарь. Так что, это не должно будет делать вычисления снова.

например. Convert (27) проверит, сопоставлено ли 27 / сохранено в словаре. Если нет, сделайте расчет и сохраните «AA» против 27 в словаре.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...