Показват се публикациите с етикет iferror. Показване на всички публикации
Показват се публикациите с етикет iferror. Показване на всички публикации

неделя, 18 март 2012 г.

#047 Търсене (трета част) Търсене в съдържанието на клетки

Продължаваме борбата с търсенето:) Отново да напомня, че въпреки "обратния" ред на подреждане на темите, е желателно да четете темите в правилния им ред (т.е. #001, #002 ...)... Често дадена тема използва по-стари "трикове".... За това не четете "новините" първо:):)

Ето задачата.... Дадени са кодове разположени в една клетка... Да се направи Vlookup подобна функция, но да търси във вътрешността на клетките....
Фигура 1: Изходни данни
Трябва да се търси в колонката "Кодове", като всеки код трябва да се третира като самостоятелна стойност!

Предварителна информация:
За търсене на текст във друг текст се използват функциите Find и Search. Разликата е в това че Find прави разлика между малки и главни букви. За повече информация ето синтаксиса им:Функция Find Функция Search.
Проблемът е, че са малко неудобни за ползване. Ако текстът го има връща число показващо къде се намира, ако обаче го няма връща грешка от тип #VALUE! а не НУЛА (както правят подобните функции в "културните" езици за програмиране)! T.e ако имате желание да правите трикове от типа Find(.....)>0 с тайната надежда да получите масив съдържащ True, False сте в грешка... Масивът ще съдържа True,#Value стойности.... По-конкретните примери ще видите как елиминирам този "бъг":):) В примера по-долу ще използвам Find по две причини: защото търся число и няма значение регистъра и защото съм мързелив и Find е по-кратка:):) Ако обаче искате търсене на съвпадение в текст без отчитане на регистъра, ще се наложи да използвате Search!

Подготовка на изходните данни:
Както се вижда кодовете са разделени със знак запетая. Това разграничава един код от друг. Важно е да не използваме на сляпо функциите за търсене, защото може да изпаднем в конфузна ситуация. Какво имам предвид.

        Проблем1: Нека да потърсим кодът "23" в изходните данни.... Ще видите че точно този текст го има както в първите пет клетки или като част на кодовете ("123"  ,  "12345" и "123456") или като самостоятелен код! Т.е. ще е груба грешка да търсим чрез =Find("23";A2)! Мисля, че се досетихте,че по-хитро ще е да търсим =Find(",23,";A2). Да търсим стойността заградена със запетайки!

        Проблем2: Когато си мислите, че всичко е цветя и рози може да се усетите, че първия и последния код в списъка не са заградени и от двете страни със запетая! Правилното търсене е =Find(",23,";"," & A2 & ",")!!! Т.е. на нас ни трябва подобрена версия на изходния списък в който нещата да са в по-стандартен вид, при който всеки код да изглежда по един и същи начин! За целта съм създал помощна колонка.
Помощна колонка
В клетката D2 е записана формулата: ="," & SUBSTITUTE(A2;" ";"") & ","
Освен, че съм добавил запетайки преди и след списъка за всеки случай съм махнал и излишните интервали от списъка с кодове (страх лозе пази):):) Разбира се тази колонка може да се намира достатъчно отдалечено от данните или да е скрита, за да не пречи на въвеждащия.Така имаме колонка в която всяка стойност е заградена със знак запетая и от двете страни! В нея ще търсим.

Именуване на области:
За по-компактни формули съм именувал областите с данни както следва:
D2:D7 - kodove (НЕ колонка А!!)
B2:B7 - gradove
C2:C7 - sumi

Резултатна таблица

Пример1 : Да се изведе името на града с даден код. Ако има дублажи да се изведе името на първия град с посочения код!
В клетка B2 формулата е: 
{=IFERROR(INDEX(gradove;MATCH(TRUE;FIND("," & A2 & ",";kodove)<>0;0));"---")}

Бележки по формулата:
  • Формулата е CSE (въвежда се със Ctrl+Shift+Enter без {})!
  • Чрез FIND("," & A2 & ",";kodove)<>0 търсим стойността от A2 (като и нея заградим в ","!!!) в кодове и чрез <>0 получаваме масив съдържащ True, #Value .... Tук не е проблем, че едната стойност е грешка. В случая на нас ни трябва True стойностите (първата True стойност)!
  • Чрез MATCH(TRUE;FIND(...)<>0;0) търсим първото появяване на TRUE в този масив... Така  получаваме реда който ни трябва..
  • INDEX(gradove;MATCH(...)) ни дава името на града.
  • "Пакетираме" с IFError да не се появяват досадните #N/A грешки (на тяхно място се появяват досадните "---":):) =IFERROR(INDEX(...);"---") 
Пример 2 : Да се изведе сумата на града с даден код. Ако има дублажи да се изведе сумата на първия град с посочения код!
 В клетка C2 формулата е:
{=IFERROR(INDEX(sumi;MATCH(TRUE;FIND("," & A2 & ",";kodove)<>0;0));"---")}
Тук няма интрига:) Формулата е аналогична на предходната. Само извличаме данните от колонка Сума.
  
Пример 3 : Да се изведе сумата на града с даден код. Ако има дублажи да се изведе сумата на ВСИЧКИ  градове с посочения код!

В клетка D2 формулата е:

{=SUMPRODUCT(--IFERROR(FIND("," & A2 & ",";kodove)<>0;False);sumi)}
Тук идеята е да "умножим" два масива . Единия масив съдържа  едно или нула  в зависимост дали кодът го има или не, а втория масив съдържа сумите. 

Бележки по формулата:
  • Формулата е CSE (въвежда се със Ctrl+Shift+Enter без {})!
  • Чрез FIND("," & A2 & ",";kodove) търсим стойността от A2 (като и нея заградим в ","!!!) в кодовете. Резултата ще е число или ГРЕШКА (вижте предварителните бележки!).
  • Чрез израза IFERROR(FIND()<>0;False) се прави"трикът" да се получи True/False масив. Ако Find върне стойност изразът Find()<>0 ще върне True, ако е грешка "пакетиращата" функция ще върне False! 
  • --IFERROR() "обръща" True/False масива в единици и нули
  • SUMPRODUCT(--IFERROR();sumi) Умножава двата масива (т.е. там където има код се взема сумата (т.е се умножава по единица), там където няма код сумата се умножава по нула). След което се  намира сумата на произведенията.


Успех...... :) :)
 

петък, 6 януари 2012 г.

#045 Data Validation без Validation!

Ето ви едно малко  по-сложно изпълнение базирано на Data Validation.

Задача: Да се реализира "Pick from Drop-down List" функционалност.
Ха сега... Няколко уводни бележки относно тази функционалност. Тези които знаят за какво иде реч да прескачат абзаца:) Когато се въвеждат стойности и сте натиснали десен бутон на мишката може ви сте видели командата Pick from Drop-down List, която показва списък на въведените до този момент стойности в колоната!

Командата в контекстното меню

Вид на списъка за избор
Това улеснение ни дава бърз начин за избиране от вече въвежданите стойности.
Hint! Вместо да се мотате из контекстното меню същия ефект се постига с натискането на ALT+Стрелка надолу!!!

След като го има защо ни трябва да го правим отново!?  Винаги съм се смятал за мързел без капка мазохистични наклонности:)

Проблем 1: Това не действа за цифрови стойности! Просто не ги показва в списъка.
Проблем 2: Ето едно писмо което получих преди време:
"..... Има едно положение в Ексел 2003, което ме затрудни. Става дума за следния казус:

Имаме таблица, в която трябва да се заключат определени области - колони, в които да се въвежда само след парола. Дотук добре - дефинираме областите в Tools/Protecton/Allow Users to Edit Ranges и слагаме пароли. След това заключваме Sheet-а от Tools/Protection/Protect Sheet. Междувременно използвам Аuto Filter във всяка колона. Това ми позволява да използвам десен бутон и Pick From Drop-down List.

И тук идва проблемът. Докато Sheet-а не беше заключен, това меню съществуваше, в момента в който я заключих, то стана неактивно. ...."

Наистина не работеше и реших да го симулирам:)

Списък в колонка C
Колонките D и E са работни може да ги сложите по-далече (може и на друг лист)! Може даже да ги скриете:)

Стъпка 1: Формула в D2-> =IF(COUNTIF($C$2:C2;C2)=1;ROW(C2);"")
Това е лесно за разбиране. Просто там където за първи път се появява дадена стойност "маркира" реда слагайки номера на реда. Размножавате формулата надолу.

Стъпка 2: Формула в E2 ->  =IFERROR(INDEX(C:C;SMALL(D:D;ROW(A1)));" ")
"Пакетиране" на уникалните стойности. Този номер ни е познат от друг цирк:):)

Стъпка 3: Декларираме име (Formulas/Define Name)  values1 с формула за Refers To:
=OFFSET(Sheet1!$E$1;0;0;50-COUNTIF(Sheet1!$E$1:$E$50;" ");1)
Това се прави за да се извлекат само клетките с конкретна стойност. Обърнете внимание, че ако горната формула върне грешка в клетката се връща ИНТЕРВАЛ! За това не минава номера с CountA.  Произволно е решено, че уникалните стойности са по-малко от 50! Ако прецените може да увеличите тази константа.

Дефиниране на име
 

Стъпка 3: Контрол на колонката C. Избираме клетките и изпълняваме Data/Data Validation

Стъпка 3.1 Избор типа на контрол:

Контрол чрез списък
Тук няма интрига:):) Използваме името за да контролираме данните.

Стъпка 3.2: Изключваме контрола при въвеждане!!!!!!
Премахване на контрола
Най-накрая си дойдохме на думата защо съм сложил това "тъпо" заглавие на темата:):):):) Всъщност Data Validation не прави никакъв контрол! Позволява да въвеждаме стойности които ги няма в списъка! Проверка няма:) Само използваме възможността да показва списък в дадената клетка! Та както виждате (може би за първи път) Data Validation без validation!:) 

Готовооо... Всяко добавено нещо се появява в списъка.... Даже числата......:)

успех

сряда, 29 юни 2011 г.

#39 Функците Small и Large без дублирани стойности

Описанието на функцията Small е дадено в помощната информация на Excel (може да използвате този адрес http://office.microsoft.com/bg-bg/excel-help/HP010062539.aspx).
За съжаление в информацията не е посочен един малък подводен камък, който  може да ви доведе до главоболие в определени случаи. Става дума за това, че функцията брои стойностите не отчитайки дублиращите стойности за всяка позиция. Ето пример:
Данни за Small
Ако въведем формулата: =SMALL(A1:A10;1) ще видим стойността на най-малката стойност (в случая 1).  Ако въведем формулата =SMALL(A1:A10;2), с тайната надежда да видим ВТОРАТА по големина стойност, ни очаква разочарование. Функцията ще върне пак 1!! Това произтича от факта, че в списъка има две единици. Чак когато зададем =SMALL(A1:A10;3) ще получим това което искаме :(

Този "проблем" се решава със следната помощна табличка:

Намиране на N-тата по големина стойност



Стъпка 1: В колонка C се намират числа от 1 до N.Може с AutoFill или формулата =Row(A1) или =Row()-1 и т.н. ( всеки си има стил и различен подход, и както и да ги въведете (дори и на ръка) никой няма да ви разстреля):):):)
Стъпка 2: В клетката D2 въведете  =SMALL($A$1:$A$10;1). Намира първата най-малка стойност. Тук няма интрига;)  
Стъпка 3: В клетка D3 въведете =SMALL($A$1:$A$10;COUNTIF($A$1:$A$10;"<="&D2)+1)
Размножете формулата като я "дръпнете" надолу. И готовото:) Ако искате да не дава грешка #Num просто я "пакетирайте" с IFError за което си има отделна тема;) 
Няколко думи за "магията". За да се намери N-тото по големина число, трябва да е намери колко е броя на N-1 по големина числа преди него! Примерно за да се намери второто по големина число трябва да се намери колко са преди него (в случая колко единици имаме)! След което към намерената бройка да се добави единица и да се намери чрез Small съответната стойност (в нашия случай 3-тото по големина число). За намирането на третото по големина числа броим колко са преди него като бройка (в нашия случай колко са числата по-малки от 2) В нашия случай намираме броя  на единиците и двойките!. Понеже имаме само една двойка сумата е 3! Т.е. със Small трябва да намерим четвъртата(!) по големина стойност.... И т.н. (опитайте се да проиграете и за останалите числа).
За по-лесното използване на тази таблица, я именуваме (примерно SmallBD).След което може да използваме "прост" Vlookup:):)

Именуване на таблицата
Пример: Да се намери петата по големина стойност: =VLOOKUP(5;SmallBD;2;FALSE). Сменяте само червената цифричка и сте готови:):)

Забележка: По някога може създаването на междинна таблица да не е възможно (въпреки че в случая го препоръчвам горещо) и се налага да се сглоби цялата формула в една клетка. В този случай формулата става доста дълга (и доста объркваща за начинаещи)! Аз ще дам само как се намира втората по големина стойност:
=SMALL($A$1:$A$10;COUNTIF($A$1:$A$10;"<=" & SMALL($A$1:$A$10;1))+1).
За по-големи стойности се въоръжете с търпение и здрави нерви и "сглобявайте":):) Но както споменах това го препоръчвам за майсторите които са разбрали предишните обяснения!

Успех:)
П.П. Всичко казано за функцията Small важи и за функцията Large!

сряда, 27 октомври 2010 г.

#034 Таблици за търсене

Този пример не бих нарекъл много триков, но от друга страна се случва доста често да се правят подобни неща. Идеята е да се реализира таблица в която търсим в първата колонка и връщаме данни от втората.
Таблица оригинал:


до 80%
2
от 81 до 99%
4
от 100 % до 119 %
6
120% и повече
8

Вариант 1: Първо ще реализираме цялата таблица с помощта само на IF. =IF(A1<=80%,2,IF(A1<100%,4,IF(A1<120%,6,8)))    * ако данните са в А1
 Този вариант е добър в случаите когато числата не се променят често, но при промяна потребителя трябва да се занимава с редактиране на формули и т.н.

Вариант 2: Таблица за търсене

Таблица за търсене
Въвеждаме данните в произволни клетки (може и на друг лист). Избираме клетките и им задаваме име (в случая  TablicaP).  NB! Не забравяйте да натискате Enter след като именувате областта!.  Обърнете внимание как е изградена таблицата спрямо основните данни! Така изградена таблицата позволява търсенето на всякакви стойности по-големи или равни на нула. 

Формулата която търси в тази таблица е :  =VLOOKUP(A1,tablicaP,2,TRUE) . Приблизително търсене чрез VLookup връщайки стойността от втора колонка (за повече  вижте помощната информация в Excel). Както казах тази формула ще работи само с неотрицателни числа! При отрицателни стойности или текст ще се издъни. Най лесно е да се "пакетира" в IFError (виж темата за тази функция). =IFERROR(VLOOKUP(A1,tablicaP,2,TRUE),0)

Вариант 3: Понеже имах цяла тема как да не се използва Vlookup ето и варианта без нея. Но в случая става доста оплетено и за предпочитане е Vlookup. Все пак ето формулата и нейната "дисекция":
=IFERROR(INDEX(tablicaP,MATCH(A1,INDEX(tablicaP,0,1),1),2),0)

INDEX(tablicaP,0,1) - Това връща цялата първа колонка от таблицата за търсене
MATCH(A1,INDEX(tablicaP,0,1),1) - Приблизително търсене на стойността от А1 в първата колонка на таблицата за търсене. Резултатът представлява номерът на намерения ред. (NB! Единицата означава приблизително търсене в подредени във възходящ ред стойности!)
INDEX(tablicaP,MATCH(A1,INDEX(tablicaP,0,1),1),2) - Връща от таблицата за търсене стойностна от намерения ред и втората колонка.

Ако сте разбрали и трите варианта нямате проблеми с търсенето (става дума за търсене в Excel а не търсене на сериозно гадже):):)



понеделник, 16 август 2010 г.

#008 Сортиране при въвеждане на данните

Тук ще покажа как може да се направи така, че данните да се сортират динамично при въвеждане на данни в дадена област.
Ето примерния лист:

Сортировка в "движение"
При промяна  (въвеждане, изтриване или редактиране) на данните в областта A:B те автоматично се появяват е зоната F:G сортирани по факултетен номер.

1. Подготовка. За по-лесно създаване на формулите ще дефинираме две динамични имена (описани в тема #001).
Име FN (факултетен номер) сочещо към =OFFSET(Sheet1!$A$2,0,0,COUNTA(Sheet1!$A:$A)-1,1)
Име Danni (факултетен номер и име на студента) сочещо към =OFFSET(Sheet1!$A$2,0,0,COUNTA(Sheet1!$A:$A)-1,2)
NB! В случая се вижда че се вади единица от броя на редовете заради заглавията на колонките!
NB! Разликата между двете имена е, че втората област се състои от две колонки (последния параметър)!

2. Формула в клетка F2 - =IFERROR(SMALL(FN,ROW(A1)),"")
Ето анализът на тази формула:
  • Променлив брояч. Row(A1). За разлика от примера с ЕГН-то тук искаме във формулата да имаме  стойност която да се се променя от едно до N в зависимост от броя на редовете в които се размножава формулата. (Ще обясня по-късно защо). Има по обикновен вариант поставяйки допълнителна колонка и в нея да се въведе стойността на брояча. Всъщност от израза Row(A1) ни интересува върната стойност 1 (реда на клетката А1) , която ще стане 2,3,4 и т.н. когато формулата се размножи надолу (А1 ще стане А2,А3 и т.н. и съответно и резултатът на Row ще се промени)...NB! Със същия успех вместо A1 може да използваме B1, X1 или която и да е клетка от първи ред.
  • Намиране на N-тата по големина стойност... SMALL(FN,ROW(A1)). За първата клетка ще върне най-малката стойност, за втората клетка втората по големина и т.н. Именно за тази цел използвахме брояча. Hint! Ако искате да се подреждат в обратен ред се използва функцията Large!
  • "Пакетираме" в IFError защото в даден момент функцията Small ще върне грешка когато в зоната няма вече стойности. (грешка #Num).
3. Формула в клетката G1. =IFERROR(VLOOKUP(F2,Danni,2,FALSE),"")
Запълването на имената става, чрез точно търсене (параметър False) с Vlookup в зоната за въвеждане. Връща се съдържането на втората колонка (в случая името). Пакетирането в IFError вече не го коментирам:)

NB! Имейте предвид, че този прмер ще работи при УНИКАЛНИ стойности в колонката която сортираме (в нашия случай Факултетен номер)! В случай на дублажи Vlookup няма правилно да определи съдържанието на втората колона.

неделя, 15 август 2010 г.

#004 Контролиране с уникален избор

#Често са ме питали как става контролиране на стойности от списък, от който дадена стойност отпада ако вече е избрана. Т.е. една стойност може да бъде избрана само един път.

Ето пример:
Да се контролира зоната A10:F10 с единичен избор от елементите от списъка в колонка I

Стъпка 1. Подготовка. Както се вижда контролираната зона е непрекъсната. Може да бъде и вертикална. Разбра се може да бъде прекъсната и "разхвърляна", но това би утежнило формулите.

Стъпка 2. Помощна колонка 1 (Колонка J). В тази колонка ще отбелязваме само елементите на списъка, които все още не са избрани. За целта в клетка J1 въвеждаме следната формула: =IF(COUNTIF($A$10:$F$10,I1) < 1,ROW(I1),""). Където A10:F10 е контролираната зона и се нуждае от настройка за вашия пример. (Hint! Ако искате даден елемент да бъде избиран не един ами 2,3 или повече пъти просто частта от формулата "<1" я променяте на "<2" , "<3" и т.н.)
Размножете ("дръпнете") формулата надолу.

Стъпка 3. Помощна колонка 2 (Колонка K). В тази колонка ще се показват сбито само нужните елементи. За целта в клетката К1 въведете следната формула: =IFERROR(OFFSET($I$1:$I$15,SMALL($J$1:$J$15,ROW(I1))-1,0,1,1),""). Размножете формулата надолу.

Стъпка 4. Дефиниране на вертикален динамичен блок. Създайте динамично име Vlist (описал съм процеса в отделна тема) със следната формула:
=OFFSET(Sheet1!$K$1,0,0,COUNT(Sheet1!$J:$J),1)
Динамична област
(NB!. Тук има малък "трик". Обърнете внимание, че данните се "вземат" от помощната колонка "К", а се броят ЧИСЛАТА (използва се Count а не CountA!) от колонка J!. Това се налага поради факта, че независимо, че не се виждат стойности в колонката К, клетките до края са запълнени с формули и Count в тази колонка винаги ще върне 15!)

Стъпка 5. Контролиране на областта с помощта на динамичния списък. Избират се клетките, които ще контролираме (в примера A10:F10) и се изпълнява командата Data/Data Validation (има отделна тема)
Контрол на областта. Предварително изберете всички клетки!
Това е:) Enjoy

#003 Функция iferror и съвместимост с по-стари версии

Една от новите функции в Excel 2007 е функцията IfError... Синтаксисът й е IFERROR(Израз,стойност)... Функцията връща стойността на израза, ако е верен, или посочената като втори параметър стойност, ако изразът е грешен... Например =IFError(A1/B1,"") е често срещано приложение, ако има вероятност в B1 да няма стойност и да възникне грешка за деление на нула. В случая при деление на нула клеткaта ще остане празна.... Ето още един пример =iferror(vlookup(a1,b1:c100,2,0),"Липсва търсената стойност"). В случая се обработва грешката #N/A (липсваща стойност) която би върнала функцията VLookup.

Както беше споменато тази функция се появи в Excel 2007. Това може да предизвика проблеми ако се прави приложение за работа с по-стари версии. Ето как се заменя тази функция: IF(ISERROR(израз),стойност,израз). Първият пример се трансформира в IF(ISERROR(A1/B1),"",A1/B1).

В примерите ще използвам IFError, но по посочения начин Вие може да си конвертирате изразите за по-голяма съвместимост.