powered by simpleCommunicator - 2.0.30     © 2024 Programmizd 02
Map
Форумы / Java [игнор отключен] [закрыт для гостей] / Генератор адресов ячеек Excel, улучшайзинг :)
14 сообщений из 14, страница 1 из 1
Генератор адресов ячеек Excel, улучшайзинг :)
    #39961550
Nixic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Всем привет! Давненько я не просил посмотреть мой диковатый код и вот :)
Задачка прилетела, в её рамках понял, что нужен некий генератор.
По факту надо не больше 20-30 адресов ячеек сгенерить, можно было тупо список захардкодить, но это ж не наш путь.
Сейчас есть косяк, что больше примерно 580 адресов генерируются долго, больше 12 секунд, а уже при 600 примерно 24 секунды, 670 уже 152 секунды.
Еще есть ограничение: адреса могут генерироваться только 2-х буквенные, то есть больше чем ZA-Z(фактически ZY это последний возможный адрес) уже не получить.
Больше чем 26 * 26 + 26 - 1 не сгенерить, т.е. 701 ячейку еще можно, при 702 уже получим ошибку(java.lang.IndexOutOfBoundsException: Index: 26, Size: 26).
А ведь у экселя xlsx 16384 столбцов судя по данным гугла.
Как они это делают :)
Задача состоит в том, что надо получить список A1, B1, C1, ... AA1, AB1, AC1, ... AAA1, AAB1, AAC1 и т.д. в общем открываем любой эксель и крутим вправо, вот весь нужный список и видно в адресах столбиков. Плюс номер строки добавить, но это не сильно важно.

На входе имеем количество необходимых адресов, на выходе лист с этими адресами, ну или массив, не суть.

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


CharUtils2
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class CharUtils2 {

    static List<String> alphabetList = IntStream.rangeClosed('A', 'Z').mapToObj(c -> "" + (char) c).collect(Collectors.toList());

    private static List<String> totalAddressList = new ArrayList<>();
    private static int alphabetSize = alphabetList.size();

    public static List<String> generateColumnAddressesWithRowNum(Integer columnCount, Integer rowNum) {
        List<String> prefixAddressList = genPrefixAddress(columnCount);
        return generateColumnAddresses(prefixAddressList, null, columnCount, rowNum);
    }

    /**
     * Генерирует префиксы для адресов ячеек которые используют 2 буквы, например AA1, AB1, BA1 и и т.д.
     * Делит количество колонок(например 57) на длину англ.алфавита(26), получает 2 полных вхождения кол-ва букв алфавита в 57 и перебором по индексу складывает префиксы в список.
     * В примере получится, что в ответе будет список A и B.
     *
     * @param columnCount количество колонок
     * @return список префиксов, A, B, C и т.д.
     */
    private static List<String> genPrefixAddress(Integer columnCount) {
        List<String> prefixAddress = new ArrayList<>();
        int alphabetSize = alphabetList.size();
        if (columnCount > alphabetSize) {
            int aCount = columnCount / alphabetSize;
            for (int i = 0; i < aCount; i++) {
                prefixAddress.add(alphabetList.get(i));
            }
        }
        return prefixAddress;
    }

    /**
     * Генерирует массив адресов ячеек в одной строке.
     *
     * @param prefixAddressList список префиксов для адресов ячеек если кол-во ячеек больше чем длина англ.алфавита(26)
     * @param prefixAddress     используется в рекурсии, для генерации адреса ячейки с префиксом, например чтобы получить AA1, AB1, AC1 и т.д.
     * @param columnCount       кол-во колонок для которого нужно сгенерировать адреса ячеек
     * @param rowNum            номер строки который будет добавлен в адреса ячеек, в конец
     * @return список сгенерированных адресов.
     */
    private static List<String> generateColumnAddresses(List<String> prefixAddressList, String prefixAddress, Integer columnCount, Integer rowNum) {
        List<String> addressList = new ArrayList<>();
        for (int i = 0; i < columnCount; i++) {
            if (alphabetSize > i) {
                String address = "";
                if (prefixAddress != null) {
                    address = prefixAddress + alphabetList.get(i);
                } else {
                    address = alphabetList.get(i);
                }
                addressList.add(address + rowNum);
            }
        }
        for (String s : addressList) {
            if (!totalAddressList.contains(s))
                totalAddressList.add(s);
        }
        if (columnCount > 0) {
            for (String prefAddr : prefixAddressList) {
                columnCount = columnCount - alphabetSize;
                generateColumnAddresses(prefixAddressList, prefAddr, columnCount, rowNum);
            }
        }
        return totalAddressList;
    }

    public static void main(String[] args) {
        long m = System.currentTimeMillis();
        List<String> strings = CharUtils2.generateColumnAddressesWithRowNum(60, 1);
        System.out.println((double) (System.currentTimeMillis() - m));
//        for (int i = 0; i < strings.size(); i++) {
//            String address = strings.get(i);
//            System.out.println(address + " [" + i + "]");
//        }
    }

}


Пока писал пост, запустил генерацию 701-го адреса, время выполнения 333 сек, последние адреса ячеек:
ZW1 [698]
ZX1 [699]
ZY1 [700]
По памяти жрет 385мб по данным VisualVM
...
Рейтинг: 0 / 0
Генератор адресов ячеек Excel, улучшайзинг :)
    #39961576
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Мне кажется можно переписать без использования коллекций типа List<String> strings
...
Рейтинг: 0 / 0
Генератор адресов ячеек Excel, улучшайзинг :)
    #39961579
artas
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Nixic,

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
 public static void main(String []args){
        for(char i = 1;i<701;i++){
            System.out.println(getNameFromNumber(i));
        }
     }
     
    public static String getNameFromNumber(int num) {
        int numeric = (num - 1) % 26;
        char letter = (char)(65 + numeric);
        int num2 = new Integer((num - 1) / 26);
        if (num2 > 0) {
            return getNameFromNumber(num2).toString() + "" + letter;
        } else {
            return letter + "";
        }
    }


алгориитм спер у великого и могучего
...
Рейтинг: 0 / 0
Генератор адресов ячеек Excel, улучшайзинг :)
    #39961582
artas
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Nixic,

проверил ща в экселе, все правильно
701 - ZY
702 - ZZ (если считать что первая кол-ка = 1)
...
Рейтинг: 0 / 0
Генератор адресов ячеек Excel, улучшайзинг :)
    #39961585
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Если заинлайнить getNameFromNumber то можно избавиться от деления и от вычисления остатка.
Они - линейно зависимы от парамтера цикла.
...
Рейтинг: 0 / 0
Генератор адресов ячеек Excel, улучшайзинг :)
    #39961589
artas
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
mayton,

я ж честно признался, мопед не мой, я с пыха только перевел. В любом случае, я думаю вопрос скорости решен
...
Рейтинг: 0 / 0
Генератор адресов ячеек Excel, улучшайзинг :)
    #39961604
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ага. Особенно эта строка радует.

Код: java
1.
int num2 = new Integer((num - 1) / 26);
...
Рейтинг: 0 / 0
Генератор адресов ячеек Excel, улучшайзинг :)
    #39961628
Nixic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
artas
mayton,
я ж честно признался, мопед не мой, я с пыха только перевел. В любом случае, я думаю вопрос скорости решен

Реально круто! Я когда гуглил что-то подобное, я искал на java, ничего толком не нашёл и написал свою дичь!))
Спасибо!
...
Рейтинг: 0 / 0
Генератор адресов ячеек Excel, улучшайзинг :)
    #39961632
chpasha
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
я уверен что в poi уже есть где-то утилитарный класс, который умеет пересчитывать координаты в excel-нотацию. надо было сразу туда копать. но иногда и самому полезно мозгами пошевелить, не без этого.
...
Рейтинг: 0 / 0
Генератор адресов ячеек Excel, улучшайзинг :)
    #39961652
Nixic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Спасибо всем, особенно artas'у, взял на вооружение (имена переменных еще надо отрефачить будет):

CharUtils2
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
import java.util.ArrayList;
import java.util.List;

public class CharUtils2 {

    /**
     * Генерирует массив адресов ячеек в одной строке.
     *
     * @param columnCount кол-во колонок для которого нужно сгенерировать адреса ячеек
     * @param rowNum      номер строки который будет добавлен в адреса ячеек, в конец
     * @return список сгенерированных адресов.
     */
    public static List<String> generateColumnAddressesWithRowNum(Integer columnCount, Integer rowNum) {
        List<String> addressList = new ArrayList<>();
        for (char i = 1; i <= columnCount; i++) {
            addressList.add(getNameFromNumber(i) + rowNum);
        }
        return addressList;
    }

    private static String getNameFromNumber(int num) {
        int columnIndex = Math.max(num - 1, 0);
        int numeric = columnIndex % 26;
        char letter = (char) (65 + numeric);
        int num2 = columnIndex / 26;
        if (num2 > 0) {
            return getNameFromNumber(num2) + "" + letter;
        } else {
            return letter + "";
        }
    }

    public static void main(String[] args) {
        long m = System.currentTimeMillis();
        int columnCount = 10000;
        int rowNum = 1;
        List<String> strings = generateColumnAddressesWithRowNum(columnCount, rowNum);
        for (String string : strings) {
            System.out.println(string);
        }
        System.out.println("Count addresses:" + strings.size());
        System.out.println("Completed for " + (double) (System.currentTimeMillis() - m) + " ms");
    }

}


Последние строчки в консоли:
NTN1
NTO1
NTP1
Count addresses:10000
Completed for 74.0 ms
...
Рейтинг: 0 / 0
Генератор адресов ячеек Excel, улучшайзинг :)
    #39961654
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Рефачь. Возми курс на экономию ресурсов памяти. Твоей утилите полезно освоить Stream-able подход к генерации информации.
Тем более что современный Java API уже к этому располагает.
...
Рейтинг: 0 / 0
Генератор адресов ячеек Excel, улучшайзинг :)
    #39961658
artas
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
chpasha,
вы правы
Код: java
1.
String columnLetter = CellReference.convertNumToColString(columnNumber);
...
Рейтинг: 0 / 0
Генератор адресов ячеек Excel, улучшайзинг :)
    #39961660
artas
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
chpasha,
brw, их реализация

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
public static String convertNumToColString(int col) {
		// Excel counts column A as the 1st column, we
		//  treat it as the 0th one
		int excelColNum = col + 1;

		String colRef = "";
		int colRemain = excelColNum;

		while(colRemain > 0) {
			int thisPart = colRemain % 26;
			if(thisPart == 0) { thisPart = 26; }
			colRemain = (colRemain - thisPart) / 26;

			// The letter A is at 65
			char colChar = (char)(thisPart+64);
			colRef = colChar + colRef;
		}

		return colRef;
	}
...
Рейтинг: 0 / 0
Генератор адресов ячеек Excel, улучшайзинг :)
    #39961679
Nixic
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Затестил код апача, он быстрее процентов на 25 работает.
Ну, буду надеятся, что полученный опыт не пропадёт, запушил вместо "своего" метода апачевский :)
...
Рейтинг: 0 / 0
14 сообщений из 14, страница 1 из 1
Форумы / Java [игнор отключен] [закрыт для гостей] / Генератор адресов ячеек Excel, улучшайзинг :)
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]