Самая быстрая функция для генерации букв столбцов 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 ]

1 голос
/ 29 декабря 2011

Вот краткая реализация с использованием LINQ.

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

Это генерирует от A до Z, затем AA до ZZ, затем AAA до ZZZ.

На моем ПК вызов GetExcelStrings().ToArray() занимает около 30 мс. После этого вы можете ссылаться на этот массив строк, если вам это понадобится тысячи раз.

1 голос
/ 10 ноября 2011

@ Нил Н - хороший код Я думаю, что в третьем письме должно быть +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();
}
0 голосов
/ 29 октября 2018

Код, который я предоставляю, НЕ является C # (вместо Python), но логику можно использовать для любого языка.

Большинство предыдущих ответов верны. Вот еще один способ преобразования номера столбца в столбцы Excel. Решение довольно простое, если мы думаем об этом как о базовом преобразовании. Просто преобразуйте номер столбца в основание 26, поскольку в нем только 26 букв. Вот как вы можете сделать это:

шаги:

  • установить столбец как частное

  • вычтите одно из фактор-переменной (из предыдущего шага), потому что нам нужно в конечном итоге получить таблицу ascii , где 97 - это.

  • разделите на 26 и получите остаток.

  • добавить +97 к остатку и преобразовать в char (поскольку 97 в таблице ASCII - "a")
  • частное становится новым частным / 26 (так как мы могли бы перейти за 26 столбец)
  • продолжайте делать это, пока частное не станет больше 0, а затем верните результат

вот код, который делает это:)

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())
0 голосов
/ 31 мая 2017

Просто используйте формулу Excel вместо пользовательской функции (UDF) или другой программы, согласно Allen Wyatt (https://excel.tips.net/T003254_Alphabetic_Column_Designation.html):

=SUBSTITUTE(ADDRESS(ROW(),COLUMN(),4),ROW(),"")

(В моей организации использование UDF было бы очень болезненным.)

0 голосов
/ 16 сентября 2013
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) ;        
}
0 голосов
/ 09 июля 2013

Почему бы нам не попробовать факториал?

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] + "";
}
0 голосов
/ 15 февраля 2013
Идея

barrowc намного удобнее и быстрее, чем любая функция преобразования! я преобразовал его идеи в реальный код C #, который я использую:

  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;
0 голосов
/ 29 ноября 2012

Мое решение:

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();
    }
}
0 голосов
/ 11 июля 2009

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

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 голосов
/ 11 июля 2009

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

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



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