Поради щодо гри в гольф у VBA


16

Схоже на це , це і це питання ...

Які загальні поради щодо гри в гольф VBA? Я шукаю ідеї, які можна застосувати до коду проблем із гольфом взагалі, які принаймні дещо специфічні VBA(наприклад, "видалити коментарі" - це не відповідь). Будь ласка, опублікуйте одну пораду на відповідь.

Хоча я працював з іншими мовами, я сильніший VBA, і VBAна цьому сайті я не бачу багатьох гольфістів .


Конвертується в Wiki спільноти відповідно до політики.
dmckee --- кошеня колишнього модератора

Вибачте, що з мого боку не було автоматичного!
Гаффі

Не біда. Насправді вони взяли сили для того, щоб відмовлятись від користувачів у питаннях CW (я думаю, ви все ще можете робити відповіді). Ви можете поставити прапор для уваги модератора, але так мало активності, як CodeGolf отримує, що навряд чи потрібно.
dmckee --- кошеня колишнього модератора

2
VBA - це відносно багатослівна мова з кількома синтаксичними ярликами. Якщо ви збираєтеся отримати найкращий рахунок, VBA може бути не найкращим вибором. Якщо ви хочете відточити свої навички, більше сил вам.
Містер Лама

2
@GigaWatt Шануй мої вміння. Насправді, зважаючи на різні виклики, я вже підібрав кілька нових хитрощів для роботи з VBA! Я не сподіваюся виграти будь-які реальні проблеми з кодовим гольфом з VBA, але це хороша практика. :-)
Гаффі

Відповіді:


8

Використовуйте за ByRefзамовчуванням під час виклику абонентів

Іноді можливо використовувати a Sub дзвінок замість а, Functionщоб зберегти кілька додаткових символів ...

Це ( 87 символів)

Sub a()
b = 0
Do Until b = 5
b = c(b)
Loop
End Sub
Function c(d)
c = d + 1
End Function

можна переробити до ( 73 символи):

Sub a()
b = 0
Do Until b = 5
c b
Loop
End Sub
Sub c(d)
d = d + 1
End Sub

Зверніть увагу, це НЕ буде циклічно назавжди, хоча, здається, ви ніколи не переставляєте bзначення.

Вищезазначене не використовує Function дзвінок, а натомість використовує функцію ByRef("За посиланням") Subвиклику. Це означає, що переданий аргумент - це та сама змінна, що і у викличній функції (на відміну від передачі ByVal"За значенням", яка є копією). Будь-які зміни передаваної змінної перейдуть до функції виклику.

За замовчуванням, приймає всі аргументи як ByRef, тому для визначення цього немає необхідності використовувати символи.

Наведений вище приклад може не відповідати ідеально для вас, залежно від значення повернення вашої функції. (тобто повернення іншого типу даних, ніж передане), але це також дає можливість отримати повернене значення, змінюючи свою початкову змінну.

Наприклад:

Sub a()
b = 0
Debug.Print c(b) ' This will print 0, and b will equal 1.'
End Sub
Function c(d)
c = d
d = d + 1
End Function

7

Напишіть і запустіть код VBA у вікні негайних

Негайне вікно оцінює будь-яку дійсну виконану версію VBA. Просто введіть оператор у «Негайне вікно», як у редакторі коду. Він швидко виконує код VBA, і він може зберегти багато додаткових символів, оскільки:

  1. Поставлення знака питання (?) На початку заяви повідомляє Негайне вікно відобразити результат вашого коду.

enter image description here

  1. У вашому коді не потрібно використовувати Sub і End Sub.

enter image description here


Ось приклад коду VBA у вікні негайних відповідей на повідомлення PPCG з тегом : Буква A без A

?Chr(88-23);

відповів Йофан .


Кредитні зображення: Excel Campus


1
Однак для цього використовується середовище REPL? Це означає, що це лише фрагмент, а не програма чи функція
caird coinheringaahing

Я думаю, що ще одним прикладом може бути те, що ви також можете створювати змінні вбудовані; наприклад, a="value":?aспочатку встановлює значення a, а потім друкує його.
Greedo

6

Умовні перевірки перед циклом

Деякі умовні перевірки є надлишковими при використанні спільно з петлями. Наприклад, aFor цикл не буде оброблятися, якщо початкова умова знаходиться поза межами запущеної умови.

Іншими словами, це ( 49 символів):

If B > 0 Then
For C = A To A + B
'...
Next
End If

Можна перетворити на це ( 24 символи):

For C = A To A + B ' if B is 0 or less, then the code continues past Next, unabated.
'...
Next

Коментар внизу невірний. Якщо B = 0, тоді вводиться цикл. pastebin.com/97MBB7hq
QHarr

5

Змінна декларація

У більшості випадків у VBA можна пропустити Option Explicit(як правило, за промовчанням у будь-якому випадку) і пропуститиDim багато своїх змінних.

Роблячи це, це ( 96 символів):

Option Explicit

Sub Test()
Dim S As String
Dim S2 As String
S = "Test"
S2 = S
MsgBox S2
End Sub

Стає таким ( 46 знаків):

Sub Test()
S = "Test"
S2 = S
MsgBox S2
End Sub

Якщо вам потрібно використовувати певні об'єкти (наприклад, масиви), вам може знадобитися Dimця змінна.


Зачекайте секунду, ви прийняли власну відповідь на своє запитання. Не круто, чувак.
Тейлор Скотт

1
@TaylorScott Це повідомлення у вікі - немає балів, і в цьому випадку немає жодної найкращої відповіді. :) Я приймаю відповідь ~ 5 років тому, щоб не мати прапор у своєму списку питань.
Гаффі

1
@TaylorScott також якщо ви приймаєте свою власну відповідь, ви не отримуєте +15 або +2 (за прийняття)
caird coinheringaahing

5

Evaluate() І []

Як уже зазначалося раніше, жорсткі коди дальності зв'язку можуть бути зменшені за допомогою квадратних дужок [A1] . Однак він має набагато більше застосувань, ніж просто це.

Відповідно до документації MSDN , Application.Evaluate()метод приймає єдиний аргумент, який є aName , як визначено умовами іменування Microsoft Excel.

NB [string]- це скорочення Evaluate("string")(зверніть увагу на"" мовні позначки, що позначають тип рядкових даних), хоча є кілька важливих відмінностей, які висвітлюються в кінці.

То що це все означає з точки зору використання?

По суті, [some cell formula here]являє собою клітинку на робочому аркуші excel, і ви можете помістити в неї майже все, що завгодно, і отримати з неї все, що можна було б із звичайною коміркою

Що входить

Підсумовуючи приклади

  • Посилання в стилі A1. Всі посилання вважаються абсолютними посиланнями.
    • [B7] повертає посилання на цю клітинку
    • Оскільки посилання абсолютні, ?[B7].Addressповернення"B$7$"
  • Діапазони Ви можете використовувати оператори діапазону, перетину та об'єднання (двокрапка, пробіл та кома відповідно) із посиланнями.
    • [A1:B5]повертає посилання на діапазон A1:B5(діапазон)
    • [A1:B5 A3:D7]повертає посилання на діапазон до A3:B5(Пересікання)
    • [A1:B5,C1:D5]повертає посилання на діапазон A1:D5(технічно A1:B5,C1:D5) (Союз)
  • Визначені імена
    • Користувацькі визначені такі як [myRange]посилання на A1: G5
    • Автоматично, як імена таблиць [Table1](можливо, менш корисні для codegolf)
    • Все, що ви можете знайти в меню [Formulas]>[Name Manager]
  • Формули
    • Дуже корисно ; будь-яка формула, яка може входити в клітинку, може входити Evaluate()або[]
    • [SUM(1,A1:B5,myRange)]повертає арифметичну суму значень у діапазонах myRange тут посилається на назву робочої книги, а не на змінну VBA
    • [IF(A1=1,"true","false")](1 байт коротший, ніж еквівалент vba Iif([A1]=1,"true","false"))
    • Формули масиву [CONCAT(IF(LEN(A1:B7)>2,A1:B7&" ",""))]- об'єднує всі рядки в діапазоні, довжина яких більша за 2 з пробілом
  • Зовнішні посилання
    • Ви можете використовувати !оператора для позначення комірки або імені, визначеного в іншій робочій книжці
    • [[BOOK1]Sheet1!A1]повертає посилання діапазону на A1 в BOOK1 або ['[MY WORKBOOK.XLSM]Sheet1!'A1]на те саме вMY WORKBOOK
    • Зверніть увагу на 'робочі зошити з пробілами в їх назвах та відсутність розширення для робочих зошитів за замовчуванням ( BOOK+n)
  • Об'єкти діаграми (див. Статтю MSDN)

NB: Я задав запитання щодо SO для цієї інформації, тому подивіться там для кращого пояснення

Що виходить

Як і у випадку, що виходить, те, що виходить, включає все, що може повернути комірка робочого аркуша. Це стандартні типи даних Excel (та їх еквіваленти VBA):

  • Логічний ( Boolean)
  • Текст ( String)
  • Числовий ( Double)
  • Error ( Variant/Error) (це непорушні помилки, тобто вони не зупиняють виконання коду, ?[1/0]виконують штрафи)

Але є кілька речей, які можна повернути, а клітини яких не можуть:

  • Посилання на діапазон ( Range) (див. Вище розділи)
  • Масиви ( Variant())

Масиви

Як було показано, []можна використовувати для оцінки формул масивів, які повертають один із стандартних типів даних Excel; наприклад, [CONCAT(IF(LEN(A1:B7)>2,A1:B7&" ",""))]яка повертається Text. Однак Evaluateтакож можна повернути масиви Variantтипу. Це можуть бути

Жорсткий код:

[{1,2;3,4}]- виводить 2D масив: ,це роздільник стовпців, ;розділяє рядки. Може вивести 1D масив

Формули масиву:

[ROW(A1:A5)]- виводить 2D масив{1,2,3,4,5} , тобто (2,1) є другим елементом (все ж деякі функції виводять 1D масиви)

  • З будь-якої причини деякі функції не повертають масиви за замовчуванням

[LEN(A1:A5)] виводить лише Довжину тексту в 1-й комірці діапазону

  • Однак їх можна примусити видавати масиви

Split([CONCAT(" "&LEN(A1:A5))]) дає 1D масив від 0 до 5, де перший елемент порожній

[INDEX(LEN(A1:A5),)]це ще одне вирішення, по суті, ви повинні використовувати функцію обробки масиву, щоб отримати бажану поведінку, що повертає масив, подібно до додавання в безглуздому, RAND()щоб зробити формули робочого аркуша мінливими.

  • Я поставив запитання щодо SO, щоб спробувати отримати кращу інформацію про це, будь ласка, відредагуйте / коментуйте кращі варіанти, якщо ви їх знайдете

Evaluate() проти []

Існує декілька відмінностей між Evaluate()та, []які слід знати

  1. Струни проти жорсткого коду
    • Мабуть, найважливіша різниця: Evaluate приймає рядок, де [] вимагав введення з жорстким кодом
    • Це означає , що ваш код може створити рядок зі змінними , наприклад , Evaluate("SUM(B1,1,"&v &",2)")буде підводити [B1], 1, 2і зміннуv
  2. Масиви

    При поверненні масиву може використовуватися лише Evaluate з індексом масиву

    v=Evaluate("ROW(A1:A5)")(1,1) ''#29 bytes

    еквівалентно

    i=[ROW(A1:A5)]:v=i(1,1) ''#23 bytes

Вибачте за пост мамонта, якщо хтось вважає, що може зробити ділянки більш короткими / якщо у вас є поради, які слід додати, тоді не соромтеся. Крім того, хоча я досліджував щось із цього, за допомогою експериментів у VBA було виявлено неабияку частину, тож якщо ви помітили помилки, відчуваючи, що щось не вистачає, не соромтесь прокоментувати / редагувати відповідно!
Greedo

1
Насправді останній розділ на масивах трохи відключений - його можна використовувати у безпосередньому вікніi=[ROW(A1:A5)]:v=i(2,1):?v
Тейлор Скотт

@TaylorScott Отже, ви можете, я абсолютно не знав, що ви можете встановити / утримувати значення змінних, які ще не були визначені, але, мабуть, це тому, що я все-таки стикаюся з 1-вкладишами негайного вікна. Оновили відповідно
Оновили

Чи працює це з Match? Я намагався, але це завжди повертає помилки. Хоча я пропускав масив замість діапазону.
seadoggie01

5

Поєднайте Nextзаяви

Next:Next:Next

Може скорочуватися до

Next k,j,i

де ітератори для Forпетель i, jі k- в такому порядку.

Наприклад нижче (69 байт)

For i=0To[A1]
For j=0To[B1]
For k=0To[C1]
Debug.?i;j;k
Next
Next
Next

Може скоротитися до 65 байт

For i=0To[A1]
For j=0To[B1]
For k=0To[C1]
Debug.?i;j;k
Next k,j,i

Що ж стосується того, як це впливає на форматування та відступ, я думаю, що найкращим підходом до цього є залишити наступне твердження із зовнішнім самим для висловлювання. Напр.

For i=0To[A1]
    For j=0To[B1]
        For k=0To[C1]
            Debug.?i;j;k
Next k,j,i

4

Зменшення Ifзаяви

При призначенні змінної використовують умовну If ... Then ... Else перевірки, ви можете зменшити кількість використовуваного коду, усунувши End If, поставивши всю перевірку на один рядок.

Наприклад, це ( 37 символів):

If a < b Then
c = b
Else
c = a
End If

Можна звести до цього ( 30 символів)

If a < b Then c = b Else c = a

Якщо у вас є кілька вкладених умовних умов, ви також можете мінімізувати їх таким чином:

If a Then If b Then If c Then Z:If d Then Y:If e Then X Else W Else V:If f Then U 'Look ma! No "End If"!

Зверніть увагу, що :дозволяє додавати більше одного рядка / команди в Ifблок.

У таких простих випадках, як правило, ви також можете видалити Else, встановивши змінну в передIf перевіркою ( 25 символів):

c = a
If a < b Then c = b

Ще краще, що вище можна звести до цього за допомогою IIf()функції ( 20 символів):

c = IIf(a < b, b, a)

3

Зменшити Range("A1") та подобаються дзвінки

Range("A1").Value(17 байт) і простіший Range("A1")(11 байт) може бути зменшений до [A1](4 байти)


2
Або взагалі, використання []для заміни Evaluate()в VBA набагато більш універсальне, ніж просто дзвінки на дальність. Наприклад, ви можете використовувати його для заміни WorksheetFunction.FuncName(args)просто [FuncName(args)], наприклад, ?[SUMPRODUCT({1,3,5},{2,7,-1})]або дуже корисного [MIN(1,2,3)]/[MAX(1,2,3)]
Greedo

Greedo, це неймовірно важлива функціональність, про яку я не знав, ви повинні додати це як свою власну відповідь.
Тейлор Скотт

1
Звичайно, незабаром я щось напишу. Так Evaluate("str")чи скорочення [str]дуже потужне в VBA, я лише нещодавно дізнався, і я здогадуюсь, що це буде корисно і для гольфу!
Greedo

Дуже корисно, достатньо, щоб я повертався до своїх відповідей, щоб побачити, чи можу я скинути свій рахунок на будь-який через це
Тейлор Скотт,

3

Видаліть пробіли

VBA автоматично відформатує, щоб додати багато інтервалів, які йому насправді не потрібні. Є відповідь на мета, яка має велике значення для мене, чому ми можемо знижувати байти, додані в автоматичному форматуванні. Важливо завжди перевіряти, що ви не видалили занадто багато. Для прикладу, ось моя відповідь, яка була зменшена майже на 22%, просто видаляючи пробіли:

Оригінальна версія: (188 байт)

Sub g(n)
For i = 0 To 1
For x = -3 To 3 Step 0.05
y = n ^ x * Cos(Atn(1) * 4 * x)
If y < m Then m = y
If i = 1 Then Cells(500 * (1 - y / m) + 1, (x + 3) * 100 + 1) = "#"
Next
Next
End Sub

Скорочена версія: (146 байт)

Sub g(n)
For i=0To 1
For x=-3To 3Step 0.05
y=n^x*Cos(Atn(1)*4*x)
If y<m Then m=y
If i=1Then Cells(500*(1-y/m)+1,(x+3)*100+1)="#"
Next
Next
End Sub

Якщо скопіювати / вставити зменшену версію в VBA, вона автоматично розшириться в оригінал. Ви можете пограти з тим, де справедливо видаляти пробіли. Ті, кого я знайшов поки що, схоже, відповідають тій схемі, де очікується, що VBA з'явиться певна команда, оскільки без неї недійсний код. Ось деякі з яких я знайшов поки що:

  • До і після будь-якої математичної операції: +-=/*^ тощо.
  • До цього To і Stepв Forзаяві:For x=-3To 3Step 0.05
  • На насправді, перед будь-яким зарезервованим словом ( To, &, Thenі т.д.) , якщо він передує буквальним , наприклад, номер,) , ?, %і т.д.
  • Після &поєднання рядків:Cells(1,1)=Int(t)&Format(t,":hh:mm:ss")
  • Після викликів функції: If s=StrReverse(s)Then
  • У межах функціональних дзвінків: Replace(Space(28)," ",0)

Правило щодо доданих символів, що не містять пробілу, шляхом автоматичного форматування. Щось на кшталт ?vs Printя бачу прийнятним, але розміщення декларації типу, як-от &відразу після змінної, наприклад, Debug.?a&"z"дає Debug.Print a&; "z". ;Характер додав має важливе значення для коду для запуску - це це ще дозволено?
Greedo

2
@Greedo Я бачу це так, як описала мета відповідь : Якщо ви можете скопіювати / вставити його в редактор, і код запуститься, це нормально. IE, якщо VBA автоматично додає символ назад, коли ви вставляєте код, то це нормально.
Інженер Тост

1
@EngineerToast ви можете впасти ще один байт від вашого прикладу: If i=1 Then може стати , If i=1Then тому що, як правило , зарезервоване слово , яке слід буквальним, будь то число, ), ?, %, .. і т.д., не повинні бути відокремлені один від одного space
Тейлор Скотт

1
@EngineerToast, ви також можете скинути байт з третьої точки кулі, оскільки ви можете опустити пробіли між )(або будь-яким іншим літералом без числа) та&
Тейлор Скотт

3

Підготуйтеся до піксельного мистецтва

Піксельне мистецтво - це напевно одна з найсильніших областей Excel, оскільки немає необхідності будувати полотно, оскільки воно вже є для вас - все, що вам потрібно зробити, - це зробити невеликі коригування

1) Складіть клітини квадратними

Cells.RowHeight=48

або, також, на 1 байт більше, але набагато простіше працювати

Cells.ColumnWidth=2

2) Розфарбуйте необхідну діапазон

Будь-який Rangeоб’єкт може бути кольоровим, зателефонувавши

`MyRangeObj`.Interior.Color=`ColorValue`

Примітка: це може і повинно поєднуватися з іншими хитрощами, відміченими на цій вікі, такими як посилання на діапазони за допомогою []позначення (наприклад [A1:R5,D6]) над використанням a Cells(r,c)або aRange(cellAddress) виклику. Крім того, як зазначено на цій вікі, це може поєднуватися з негативним значенням кольору, щоб зменшити розмір кольорових посилань

Швидкі посилання

Посилання на діапазон

На клітинку A1можна посилатися будь-яким із наведених нижче способів

Range("A1")
Cells(1,1)
[A1]

і на Діапазон A1:D4може бути посилатися будь-яким із наступних способів

Range("A1:D4")
Range("A1").Resize(4,4)
Cells(1,1).Resize(4,4)
[A1].Resize(4,4,)
[A1:D4]

Кольоровий довідник

Black  0
White  -1
Red    255
Aqua   -256

3

Спростіть вбудовані функції

Використовуючи певні функції часто, переназначте їх на визначену користувачем функцію.

Наступний код ( 127 знаків) можна зменшити з:

Sub q()
w = 0
x = 1
y = 2
z = 3
a = Format(w, "0.0%")
b = Format(x, "0.0%")
c = Format(y, "0.0%")
d = Format(z, "0.0%")
End Sub

до ( 124 знаків):

Sub q()
w = 0
x = 1
y = 2
z = 3
a = f(w)
b = f(x)
c = f(y)
d = f(z)
End Sub
Function f(g)
f = Format(g, "0.0%")
End Function

Поєднуючи це з трюком ByRef , ви можете зберегти ще більше символів (до 114 ):

Sub q()
w = 0
x = 1
y = 2
z = 3
a = f(w)
b = f(x)
c = f(y)
d = f(z)
End Sub
Sub f(g)
g = Format(g, "0.0%")
End Sub

Робіть це розсудливо, оскільки VBA має багато символів для визначення а Function. Другий блок коду насправді буде більшим, ніж перший, при будь-якій кількості менших Format()викликів.


2
в останньому вам не потрібен дзвінок про призначення, тобто a = f(w)його можна зменшити доf w
Тейлор Скотт

3

STDIN і STDOUT

Введення в Subпідпрограми та Functions за допомогою вхідних змінних

Public Sub A(ByRef B as String)

Може бути зменшено до

Sub a(b$) 

The PublicіByRef дзвінки за замовчуванням для VBA і , таким чином , неявно, і може (майже) завжди бути відкинутий.

Буквальні $сили типу bмають бути типуString .

Літерали інших типів

  • ! Неодружений
  • @ Валюта
  • # Подвійний
  • % Цілий
  • $ Рядок
  • & Довго
  • ^ LongLong (лише 64 біт)

Крім того, загальновизнано, що ви можете залишити вхідну змінну як тип за замовчуванням, Variantа будь-які помилки на основі типу залишити без обробки. Напр. Sub E(F)в якому Fочікується тип Boolean[](який буде переданий у звичайний режим E Array(True, False, False))

Введення в Subпідпрограми та функції негайних вікон черезCells

VBA не має повністю функціональної консолі і, таким чином, не має жодної офіційної STDIN, і, таким чином, дозволяє використовувати деякі гру з прохідним входом.

За винятком, прийнято приймати дані з комірки або діапазону комірок, що може бути зроблено так

s=[A1]

яка неявно ставить .valueз комірки [A1](на яку також можна посилатися як cells(1,1)абоrange("A1")

Приклад Проблема: Відобразить вхід у полі повідомлень

Через підпрограму Sub A:msgbox[A1]:End Sub

Через функцію вікна негайно msgbox[A1]

Введення через умовні аргументи компіляції

Проекти VBA підтримують отримання аргументів з командного рядка або через Властивості VBAProject (перегляд через провідник проектів -> [Ваш проект VBA] - (клацніть правою кнопкою миші) -> Властивості VBAProject -> Аргументи умовної компіляції)

Це багато в чому корисно для викликів коду помилок

Враховуючи аргумент умовного компіляції n=[some_value], це дозволяє виконувати код, який створить код помилки, виходячи зі значення n. Зауважте, це вимагає додавання до вашого коду 2-х байт n=у розділі умовних аргументів компіляції на панелі властивостей VBAProject.

Приклад коду

...
#If n=3 then
return ''  Produces error code '3', Return without GoSub
#ElseIf n=20 then
resume ''  Produces error code '20', Resume without Error
#EndIf
...

Виведення через значення функції

Тут багато чого сказати, загальна форма цитованих нижче приблизно така ж компактна, наскільки це можна зробити.

Public Function A(b)
    ...
    A=C
End Function

ПРИМІТКА: у переважній більшості випадків більш байт перетворює метод у підпрограму та виводить у вікно безпосередніх VBE (див. Нижче)

Виведення з Subпідпрограм та Functions через вікно негайних VBE

Виведення до прямого вікна VBE (AKA the WB Debug Window) є загальним методом виводу VBA для текстових викликів, однак, важливо пам’ятати, що Debug.Print "Text"виклик може бути значно полегшеним.

Debug.Print "Text"

функціонально ідентичний

Debug.?"Text"

як ?автоформати до Print.

Виведення з Subпідпрограм та функцій вікна негайних негайних VBE за допомогою інших методів

У рідкісних випадках, коли ситуація справді правильна, ви можете взяти інформацію з деяких більш тривіальних входів, доступних для VBA, таких як регулятор розміру шрифту, селектор шрифту та масштабування. (Наприклад, імітація вибору розміру шрифту Word )


2

Коротка примітка про форматування

Тому що StackExchange використовує Markdown та Prettify.js ви можете додати мовний прапор до ваших відповідей щодо кодування, що, як правило, робить їх більш професійними. Хоча я не можу гарантувати, що це поліпшить вас в гольфі в VBA, я можу гарантувати, що це зробить вас схожим на ви.

Додавання будь-якого з прапорців нижче перетвориться

Public Sub a(ByRef b As Integer) ' this is a comment

до

Public Sub a(ByRef b As Integer) ' this is a comment

Мовні теги VBA

<!-- language: lang-vb -->

<!-- language-all: lang-vb -->

Примітка: останній перетворює всі сегменти коду у вашій відповіді, тоді як попередній перетворює лише негайно наступні сегменти коду


lang-vbтак? - Дивно, що це формати краще, ніж lang-vbaдля відповіді на vba.
Greedo

1
@Greedo, це тому, що, хоча lang-vbaнадаватимуть підсвічування, насправді це лише підсвічування за замовчуванням. Мабуть, VBA насправді не було впроваджено у Prettify.js, тому нам доведеться дотримуватися виділення VB
Тейлор Скотт

2

Кілька If .. Thenперевірок

Як і в інших мовах, кілька Ifперевірок зазвичай можуть бути об'єднані в один рядок, що дозволяє використовувати And/ Or(тобто &&/ ||в C та інших), який у VBA замінює і a, Thenі an End If.

Наприклад, із вкладеними умовними ( 93 символи):

'There are MUCH easier ways to do this check (i.e. a = d).
'This is just for the sake of example.
If a = b Then
    If b = c Then
        If c = d Then
            MsgBox "a is equal to d"
        End If
    End If
End If

може стати ( 69 символів):

If a = b And b = c And c = d Then
    MsgBox "a is equal to d"
End If

Це також працює з невкладеними умовами.

Поміркуйте ( 84 знаків):

If a = b Then            
    d = 0
End If

If c = b Then            
    d = 0
End If

Це може стати ( 51 знак):

If a = b Or c = b Then            
    d = 0
End If

1
у викладі If -, тоді частина "End - if" не є обов'язковою, якщо ви пишете код в одному рядку.
Stupid_Intern

@newguy Правильно. Дивіться також цю іншу відповідь: codegolf.stackexchange.com/a/5788/3862
Gaffi

Виклад вище можна скоротити далі доd=iif(a=b or c=b,0,d)
Тейлор Скотт

2

Кінцеві Forпетлі

При використанні Forциклів, aNext рядку не потрібна назва змінної (хоча це, мабуть, краще використовувати в звичайному кодуванні).

Тому

For Variable = 1 to 100
    'Do stuff
Next Variable

можна скоротити до:

For Variable = 1 to 100
    'Do stuff
Next

(Економія залежить від вашої назви змінної, хоча якщо ви займаєтесь гольфом, це, мабуть, лише 1 символ + 1 пробіл.)


1
2 символи, не забудьте порахувати пробіл!
11684

Мені трапляється майже ніколи не ідентифікувати змінну, навіть у звичайному коді!
день

2

Розбийте рядок на масив символів

Іноді це може бути корисно, щоб розділити рядок на окремі символи, але це може зайняти трохи коду, щоб зробити це вручну в VBA.

ReDim a(1 To Len(s))
' ReDim because Dim can't accept non-Const values (Len(s))
For i = 1 To Len(s)
    a(i) = Mid(s, i, 1)
Next

Натомість ви можете використовувати одну лінію, відносно мінімальну ланцюжок функцій, щоб виконати роботу:

a = Split(StrConv(s, 64), Chr(0))

Це призначить ваш рядок sдля Variantмасиву a. Однак будьте обережні, оскільки останній елемент масиву буде порожнім рядком ( ""), з яким потрібно буде оброблятись належним чином.

Ось як це працює: StrConvФункція перетворює a Stringв інший формат, який ви вказуєте. У цьому випадку 64 = vbUnicode, тому він перетворюється у формат унікоду. При роботі з простими рядками ASCII результат - нульовий символ (не порожній рядок ""), що вставляється після кожного символу.

Далі Splitбуде перетворено отриманий результат Stringу масив, використовуючи нульовий символChr(0) як роздільник.

It is important to note that Chr(0) is not the same as the empty string "", and using Split on "" will not return the array you might expect. The same is also true for vbNullString (but if you're golfing, then why would you use such a verbose constant in the first place?).


You should mention that the resulting array has an additional empty string at the end.
Howard

@Howard Yes, I should. It was in my head while I was typing this up, must have slipped my mind.
Gaffi

2

Using With (Sometimes! See footnote)

Using the With statement can reduce your code size significantly if you use some objects repeatedly.

i.e. this (80 chars):

x = foo.bar.object.a.value
y = foo.bar.object.b.value
z = foo.bar.object.c.value

can be coded as (79 chars):

With foo.bar.object
    x = .a.value
    y = .b.value
    z = .c.value
End With

The above isn't even the best-case scenario. If using anything with Application, such as Excel.Application from within Access, the improvement will be much more significant.


*Depending on the situation, With may or may not be more efficient than this (64 chars):

Set i = foo.bar.object
x = i.a.value
y = i.b.value
z = i.c.value

2

Infinite Loops

Consider replacing

Do While a<b
'...
Loop

or

Do Until a=b
'...
Loop

with the antiquated but lower byte count

While a<b
'...
Wend

If you need to exit a Sub or Function prematurely, then instead of Exit ...

For i=1To 1000
    If i=50 Then Exit Sub
Next

consider End

For i=1To 1E3
    If i=50 Then End
Next

Note that End halts all code execution and clears out any global variables, so use wisely


You should consider rewriting the last section (For and End) to reflect that the case 100 will never be met and adds an unecessary byte
Taylor Scott

Also, while this is very legible, you may consider removing the whitespace to show the possible benefits of these methods better (it is always good to abuse the autoformatting in VBA for codegolfing)
Taylor Scott

2

Use Spc(n) over Space(n), [Rept(" ",n)] or String(n," ")

When trying to insert several spaces of length n, use

Spc(n)              ''  6  bytes

over

B1=n:[Rept(" ",B1)] ''  19 bytes
String(n," ")       ''  13 bytes
Space(n)            ''  8  bytes

Note: I am not sure why, but it seems that you cannot assign the output of Spc(n) to a variable, and that it must rather be printed directly - so in certain cases Space(n) is still the best way to go.


2

Reduce Debug.Print and Print calls

Debug.Print [some value] 

(12 Bytes; note the trailing space) may be reduced to

Debug.?[some value]

(7 Bytes; note the lack of trailing space).

Similarly,

Print 

(6 Bytes) may be reduced to

?

(1 Byte).

Furthermore, when operating in the context of an anonymous VBE immediate window function the Debug statement may be dropped entirely, and instead printing to the VBE immediate window via ? may be assumed to be STDIN/STDOUT

Special characters

When printing strings you can also use special characters in place of &. These allow for alternate formats in what's printed or whitespace removal

To join variable strings, instead of

Debug.Print s1 &s2

You can use a semicolon ;

Debug.?s1;s2

This semicolon is the default behaviour for consecutive strings, as long as there is no ambiguity So these are valid:

Debug.?s1"a"
Debug.?"a"s1

But not

Debug.?s1s2 'as this could be interpreted as a variable named "s1s2", not 2 variables
            'use Debug.?s1 s2 instead (or s1;s2)
Debug.?"a""b" 'this prints a"b, so insert a space or ; for ab

Note that a ; at the end of a line suppresses a newline, as newlines are by default added after every print. Counting bytes returned by VBA code is under debate

To join with a tab use a comma , (actually 14 spaces, but according to )

Debug.?s1,s2 'returns "s1              s2"

Finally, you can use type declarations to join strings instead of ;, each having its own slight effect on formatting. For all of the below a = 3.14159 is the first line

Debug.?a&"is pi" -> " 3 is pi" 'dims a as long, adds leading and trailing space to a
Debug.?a!"is pi" -> " 3.14159 is pi" 'dims a as single, adds leading and trailing space
Debug.?a$"is pi" -> "3.14159is pi" 'dims a as string, no spaces added

2

Use a helper Sub to Print

If the code requires using more than six Debug.? statements you can reduce bytes by replacing all Debug.? lines with a call to a Sub like the one below. To print a blank line you need to call p "" since a parameter is required.

Sub p(m)
Debug.?m
End Sub

1
To print a new line with that you would only need p"" or if it can be unterminated, p". However, in the vast majority of cases where this may apply, it makes more sense to use a string variable and only print the string variable at the end.
Taylor Scott

1

Use Array() Choose() instead of Select or If...Then

When assigning a variable based on a the value of another variable, it makes sense to write out the steps with If...Then checks, like so:

If a = 1 Then
b = "a"
ElseIf a = 2 Then
b = "c"
'...
End If

However, this can take up a lot of code space if there are more than one or two variables to check (there are still generally better ways to do even that anyway).

Instead, the Select Case statement helps reduce the size of the checks by encasing everything in one block, like so:

Select Case a
Case 1:
b = "a"
Case 2:
b = "c"
'...
End Select

This can lead to much smaller code, but for very simple cases such as this, there is an even more efficient method: Choose() This function will pick a value from a list, based on the value passed to it.

b = Choose(a,"a","c",...)

The option to select (a in this case) is an integer value passed as the first argument. All subsequent arguments are the values to choose from (1-indexed, like most VBA). The values can be any data type so long as it matches the variable being set (i.e. objects don't work without the Set keyword) and can even be expressions or functions.

b = Choose(a, 5 + 4, String(7,"?"))

An additional option is to use the Array function to get the same effect while saving another character:

b = Array(5 + 4, String(7,"?"))(a)

An interesting and possibly very beneficial use for golfing is to use this in conjunction with an IIf() or another Choose(): A1=IIf(a=Choose(b,c,d,e),Choose(Choose(f,g,h,i),j,k,l),Choose(IIf(m=n,Choose(p,q,r,s),IIf(t=u,v,w)),x,y,z))
Gaffi

1

Bit-Shifted RGB Values

Because of the way that Excel handles colors, (unsigned, 6-character hexadecimal integer) you can make use of negatively signed integers, of which excel will only use the right 6 bytes to assign a color value

This is a bit confusing so some examples are provided below

Lets say you want to use the color white, which is stored as

rgbWhite

and is equivalent to

&HFFFFFF ''#value: 16777215

to golf this down all we need to do is find a negative hexadecimal value which terminates in FFFFFF and since negative Hex values in must be in the format of FFFFXXXXXX (such that X is a valid hexadecimal) counting down from FFFFFFFFFF (-1) to FFFF000001 (-16777215)

Knowing this we can generalize that the formula

Let Negative_Color_Value = -rgbWhite + Positive_Color_Value - 1
                         = -16777215 + Positive_Color_Value - 1
                         = -16777216 + Positive_Color_Value

Using this, some useful conversions are

rgbWhite = &HFFFFFF = -1 
rgbAqua  = &HFFFF00 = -256
16747627 = &HFF8C6B = -29589

Good to know what was going on there, I just discovered it by accident in that question - but this clear explanation shows exactly how it works. Another thing to bear in mind is that certain key colours can be reduced with mathematical operators; rgbWhite=2^24-1 although could possibly be reduced further if you miss off the -1 to get roughly there
Greedo

1
In fact, here is a list of colours with their mathematical representations, which are shorter than either the positive or negative decimal versions: &000080: 2^7, &000100: 2^8, &000200: 2^9, &000400: 2^10, &000800: 2^11, &001000: 2^12, &002000: 2^13, &004000: 2^14, &008000: 2^15, &010000: 2^16, &01FFFF: 2^17-1, &020000: 2^17, &03FFFF: 2^18-1, &040000: 2^18, &07FFFF: 2^19-1, &080000: 2^19, &0FFFFF: 2^20-1, &100000: 2^20, &1FFFFF: 2^21-1, &3FFFFF: 2^22-1, &400000: 2^22, &7FFFFF: 2^23-1 n.b. not necessarily complete, but I think I did a fairly thorough job
Greedo

1

Omit terminal " when printing to Immediate Window

Given the function below, which is to be used in the debug window

h="Hello":?h", World!"

The Terminal " may be dropped for -1 Byte, leaving the string unclosed and the program shall execute the same, without error

h="Hello":?h", World!

Even more surprising than this is that this may be done within fully defined subroutines.

Sub a
h="Hello":Debug.?h", World!
End Sub

The subroutine above runs as expected and autoformats to

Sub a()
h = "Hello": Debug.Print h; ", World!"
End Sub

1

Use Truthy and Falsey Variables in conditionals

Sometimes called implicit type conversion - directly using a number type in a If,[IF(...)] or IIf(...) statement, by using the truthy and falsey nature of that number can absolutely save you some bytes.

In VBA, any number type variable that is non-zero is considered to be truthy ( and thus zero, 0, is the only value falsey) and thus

If B <> 0 Then 
    Let C = B
Else 
    Let C = D
End If 

may be condensed to

If B Then C=B Else C=D

and further to

C=IIf(B,B,D)

1

Address Sheets By Name

Instead of Addressing a WorkSheet object by calling

Application.ActiveSheet
''  Or 
ActiveSheet   

One may use

Sheets(n)  ''  Where `n` is an integer
''  Or 
[Sheet1]

Or More preferably one may access the object directly and use

Sheet1

1

Exponentiation and LongLongs in 64-Bit VBA

The general form of exponentiation,

A to the power of B

Can be represented as in VBA as

A^B 

But Only in 32-Bit Installs of Office, in 64-Bits installs of Office, the shortest way that you may represent without error this is

A ^B

This is because in 64-Bit versions of VBA ^ serves as both the exponentiation literal and the LongLong type declaration character. This means that some rather odd-looking but valid syntax can arise such as

a^=2^^63^-1^

which assigns variable a to hold the max value of a Longlong


1

Compress Byte Arrays as String

For challanges that require the solution to hold constant data, it shall may be useful to compress that data as a single string and to then iterate across the string to fetch the data.

In VBA, any byte value may be directly converted to a character with

Chr(byteVal)

And a long or integer value may be converted to two characters with

Chr(longVal / 256) & Chr(longVal Mod 256)

So for a byte array a compression algorithm would look something like

For Each Var In bytes
    Select Case Var
        Case Is = Asc(vbNullChar)
            outstr$ = outstr$ & """+chr(0)+"""
        Case Is = Asc(vbTab)
            outstr$ = outstr$ & """+vbTab+"""
        Case Is = Asc("""")
            outstr$ = outstr$ & """"""
        Case Is = Asc(vbLf)
            outstr$ = outstr$ & """+vbLf+"""
        Case Is = Asc(vbCr)
            outstr$ = outstr$ & """+vbCr+"""
        Case Else
            outstr$ = outstr$ & Chr$(Var)
    End Select
Next
Debug.Print "t="""; outstr$

Noting that the Select Case section is implemented due to the characters which may not be stored as literals in the string.

From the resulting string, which will look something like

t="5¼-™):ó™ˆ"+vbTab+"»‘v¶<®Xn³"+Chr(0)+"~ίšÐ‘š;$ÔÝ•óŽ¡¡EˆõW'«¡*{ú{Óx.OÒ/R)°@¯ˆ”'®ïQ*<¹çu¶àªp~ÅP>‹:<­«a°;!¾y­›/,”Ì#¥œ5*B)·7    

The data may then be extracted using the Asc and Mid functions, eg

i=Asc(Mid(t,n+1))

1

Use Improper Constants

VBA allows, in some cases, for the use of unlisted or improper constants in expressions which require constant values. These are often legacy values, and shorter in length than the proper values.

For example the values below may be used when letting a value be held by the rng.HorizantalAlignment property.

ImproperProperGeneral ConstantxlHAlign  Constant11xlGeneralxlHAlignGeneral24131xlLeftxlHAlignLeft34108xlCenterxlHAlignCenter44152xlRightxlHAlignRight55xlFillxlHAlignFill64130xlJustifyxlHAlignJustify77xlCenterAcrossSelectionxlHAlignCenterAcrossSelection84117xlDistributedxlHAlignDistributed

This means, for example that setting a cell to having its text centered with

rng.HorizantalAlignment=-4108

may be shortened down to

rng.HorizantalAlignment=3

by replacing the improper constant value 3 for the proper value -4108. Note that if you fetch the rng.HorizantalAlignment property value, it will return the proper value. In this case, that would be -4108.


1

In Excel, Create Numeric Arrays by Coercing Ranges

When a constant single dimensional set of numerics of mixed length, S is needed, it shall be more efficient to use [{...}] notation to declare a range and then coerce that into a numeric array rather than to use the Split(String) notation or similar.

Using this method, a change of Δbyte count=5 bytes shall be accrued for all S.

Example

For instance,

x=Split("1 2 34 567 8910")

may be written as

x=[{1,2,34,567,8910}]

It is further worth noting that while this method does not allow for direct indexing, it does allow for iteration over the for loop directly, ie

For Each s In[{1,3,5,7,9,2,4,6,8}]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.