Microsoft #Excel – Spreadsheet Compare

De foarte multe ori în activitățile noastre zilnice realizăm foi de calcul în Excel pe care le modificăm pe parcursul mai multor zile. În lipsa unui sistem de management al documentelor (gen SharePoint on-premises sau din Office 365), o practică defectuoasă, frecvent întâlnită, este aceea de a salva același fișier cu nume diferite și stadii diferite ale documentului: Listapreturi v1, Listapreturi final, Lista preturi final v2, și așa mai departe. Dacă trebuie să trimitem același fișier pentru modificări și revizii la alți colegi sau chiar la parteneri externi, manipularea datelor devine și mai greoaie, pentru că trebuie să identificăm modificările efectuate.

Nu știu câți dintre cititori folosesc utilitarul Spreadsheet Compare din edițiile 2013 și mai noi ale pachetelor Office. Acest articol își propune să prezinte sumar acest utilitar.

Dacă nu aveți instalat acest instrument pe calculator puteți opta pentru versiunea de control a versiunilor cu ajutorul funcției IF().

În exemplul din acest articol dispun de două versiuni ale aceluiași fișier, format din două foi de calcul: Lista stocuri V1.xlsx și Lista stocuri V2.xlsx salvate local în același director. Ele pot fi stocate și pe discuri diferite.

Pentru a deschide utilitarul dați click pe butonul Start și tastași numele utilitarului după care îl deschideți.

După deschidere apăsați butonul Compare Files și căutați cele două fișiere pe disc.

Puteți compara doar două fișiere odată, nu mai multe.

Apăsați apoi Ok și așteptați.

Fereastra de rezultat este împărțită în mai multe zone: conținutul celor două fișiere cu evidențierea modificărilor, zona de opțiuni pentru modificări, zona de detalii ale modificărilor și statistici cu numărul de modificări.

În imagine este specificat faptul că în a doua foaie de calcul a fost adăugată o nouă linie și apar valori diferite în fișierul al doilea prin introducerea lor (cele cu verde) sau valori modificate de formule în urma modificării valorilor introduse (cele cu turcoaz… – bărbații căsătoriți mă înțeleg ).

Opțiunile de afișare pot fi activate sau dezactivate din meniul de culori din partea stângă jos pentru a reflecta exact ceea ce dorim să evidențiem.

Operațiunile de Export a rezultatelor din meniu: Export Results și Copy Results to Clipboard pot fi utile în operațiunile de auditare a modificărilor și o evidențiere în timp a acestora.

În cazul în care fișierele Excel sunt protejate cu parole la deschidere, se pot gestiona parolele de acces cu ajutorul butonului Options, secțiunea Passwords.

Specificul secțiunii de parole este că ele nu sunt asociate unui fișier ci pur și simplu putem trece o listă de parole pe care le folosim la fișiere. Utilitarul încearcă toate parolele pe rând pentru a deschide fișierele.

 

Sper să vă fie util!

Clasament mini campionat de fotbal – Problemă de #Excel [Update]

Salutare fanilor Excel și celor în devenire. :)

Astăzi am primit o altă problemă interesantă de Excel cu aplicabilitate destul de mare. Este vorba de înregistrarea scorurilor la mini campionatele de fotbal și stabilirea clasamentelor în timp real.

De asemenea, ar fi interesant dacă primim soluții alternative pentru Google Spreadsheets.

Exemplu de tabel pentru înregistrare rezultate:

Exemplu de clasament:

Clasamentul (Rank) se stabilește în ordine în funcție de numărul de Puncte, Victorii, Golaveraj. Nice to have: În condiții de egalitate perfectă între două echipe, departajarea să se facă în funcție de meciul direct.

Soluția trebuie transmisă prin e-mail la adresa: valy.greavu@outlook.com până pe data de 05.04.2019 ora 22:00.

Dacă sunt studenți ai mei în anul I care rezolvă și știu să-mi explice rezolvarea vor primi 10 la examenul de Excel!

Dacă există sponsori care doresc să premieze (simbolic) oamenii care rezolvă astfel de probleme, vă rog să mă contactați.

Succes și așteptăm! :)

PS. Nu dați răspunsurile în comentarii… Scrieți până în data anunțată doar întrebări/sugestii/opinii.

[UPDATE 08.04.2019]

După mai mult de 24 de ore de la lansare am primit mai multe soluții pentru această problemă, fiecare cu modul ei specific de implementare.

Modelul propus de mine include o interogare PowerQuery bazată pe append-ul dintr-un tabel în altul în forma unei a treia sursă care este afișată în fișierul Excel sub forma imaginii de mai sus.

Așa cum era de așteptat prima soluție a sosit de la CiprianS care a propus două metode de rezolvare: o metodă doar bazată pe formulele CountIFS() si SumIFS() care are mai multe avantaje: poate fi utilizată în orice mediu SpreadSheet inclusv Google sau alt Excel On-line. De asemenea, această demonstrație denotă faptul că problema era accesibilă unui număr mare de utilizatori Excel care ar fi putut încerca abordarea problemei. Dezavantajul metodei este că de fiecare dată când se modifică/actualizează tabelul de scoruri trebuie refăcut sort-ul la tabelul de rezultate.

A doua metodă este foarte asemănătoarea cu soluția propusă de mine, aceea de a folosi PowerQuery. Soluția propusă de CiprianS poate fi descărcată aici. Dezavantajul cu PowerQuery este că după ce se schimbă scorurile trebuie dat refresh pe tabelul de date.

A doua soluție cu o abordare complet diferită a sosit de la Adrian B, care a calculat clasamentul printr-un macro. Fișierul este verificat și poate fi deschis fără probleme. Soluția propusă de Adrian poate fi descărcată aici. Pentru cei care vor să studieze macro-ul propus și nu știți cum să îl deschideți: Alt+F11 și îl găsiți în Shee1 (Soccer)

Marele avantaj al soluției este că realizează actualizarea clasamentului în timp real în funcție de schimbarea scorurilor sau înregistrarea altor meciuri.

Dezavantaje: Nu poate fi folosit on-line și nu poate fi deschis pe calculatoarele care au blocate Macros din surse externe.

O altă soluție a fost primită de la CiprianT din Iași, o soluție bazată pe formule și care poate fi folosită în Google sau alt Excel on-line, dazavantajul fiind faptul că folosește prea multe coloane și tabele intermediare.

 

 

Dacă ar fi să spun cine a câștigat, voi spune că toți cei care și-au antrenat neuronii în căutarea unei rezolvări, dar și cei care pot folosi modelele propuse de CiprianS și AdrianB.

Sper să fie util cuiva!

Căutarea în Matrice – Problemă de #Excel [Updated]

Articolul a fost actualizat pe data de 22.03.2019 Ora 22:00. Soluțiile mai jos.

Salutare tuturor fanilor Excel … care au mai rămas pe aici. Astăzi am primit o problemă interesantă de Excel pe care v-o supun atenției și vouă.

Se dă următoarea matrice:

Valori/Ziua Z1 Z2 Z3 Z4 Z5 Z6 Z7 Z8 Z9 Z10
O1           A        
O2   A A           A  
O3     B A       A    
O4     C C            
O5   B   B           B
O6 A         C        
O7     D              
O8       D     B     D
O9 C                  
O10           D        

Realizați un raport de sinteză cu următoarea structură și care să aibă rezultatul în formatul următor:

Ziua/Count A B C D
Z1 O6 O9
Z2 O2 O5
Z3 O2 O3 O4 O7
Z4 O3 O5 O4 O8
Z5
Z6 O1 O6 O10
Z7 O8
Z8 O3
Z9 O2
Z10 O5 O8

Soluția trebuie transmisă prin e-mail la adresa: valy.greavu@outlook.com până pe 22.03.2019 ora 22:00. Dacă sunt studenți ai mei în anul I care rezolvă și știu să-mi explice rezolvarea vor primi 10 la examenul de săptămâna viitoare!

Fișierul cu rezolvarea mea poate fi descărcat de aici.

Aștept cu interes!

[UPDATE] Soluții

În decursul celor 30 de ore cât a fost disponibilă problema spre rezolvare, am primit 4 soluții de la oameni extraordinari de buni în Excel, cu unii dintre ei am mai reacționat în timp. Nu știu dacă mai sunt și alții care au mai încercat, dar pe baza numărului de vizualizări, tind să cred că au fost destul de puțini. Îi încurajez pe toți cei care vor să încerce să îmi ceară feedback pe parcurs…

Problema a fost expusă doar pe jumătate. Jumătatea în care fiecare valoare apare doar odată pe coloană. Pentru a rezolva această problemă lucrurile sunt simple. Se folosește o funcție Index combinată cu un match pe un offset dinamic generat de valorile corespunzătoare coloanei pe care se află valoarea.

Soluția mea

În exemplul meu, formula pentru celula B15, echivalentă combinației Z1/A este:

=IFNA(INDEX($A$1:$A$11;MATCH(B$14;OFFSET($A$1;0;MATCH($A15;$A$1:$K$1;0)-1;COUNTA($A$1:$A$11);1);0));"")

în care:

formula OFFSET() se folosește pentru a determina coloana de căutare a MATCH-ului pe B$14. Acest offet este determinat de MATCH-ul său intern ($A15) și are numărul echivalent al liniilor determinate de COUNTA.

Pentru varianta cu duplicate (și aici m-am oprit cu formulele… adică nu am formulă pentru mai mult de două valori) treaba se complică foarte mult. Pe lângă faptul că trebuie să continue căutarea trebuie adăugat și un separator de valori (în cazul meu virgulă) care trebuie eliminat din valorile nule sau singulare.

În fișierul care poate fi descărcat mai sus, formula pentru duplicate este de forma:

=IF(
RIGHT(CONCATENATE(IFNA(
INDEX($A$1:$A$11;MATCH(B$14;OFFSET($A$1;0;MATCH($A15;$A$1:$K$1;0)-1;COUNTA($A$1:$A$11);1);0));"");",";
IFNA(INDEX(OFFSET($A$1;MATCH(B$14;OFFSET($A$1;0;MATCH($A15;$A$1:$K$1;0)-1;COUNTA($A$1:$A$11);1);0);0;COUNTA($A$1:$A$11);1);
MATCH(B$14;OFFSET($A$1;MATCH(B$14;OFFSET($A$1;0;MATCH($A15;$A$1:$K$1;0)-1;COUNTA($A$1:$A$11);1);0);MATCH($A15;$A$1:$K$1;0)-1;COUNTA($A$1:$A$11);1);0));"") ))=",";

IFNA(INDEX($A$1:$A$11;MATCH(B$14;OFFSET($A$1;0;MATCH($A15;$A$1:$K$1;0)-1;COUNTA($A$1:$A$11);1);0));"");

CONCATENATE(IFNA(INDEX($A$1:$A$11;MATCH(B$14;OFFSET($A$1;0;MATCH($A15;$A$1:$K$1;0)-1;COUNTA($A$1:$A$11);1);0));"");",";IFNA(INDEX(OFFSET($A$1;MATCH(B$14;OFFSET($A$1;0;MATCH($A15;$A$1:$K$1;0)-1;COUNTA($A$1:$A$11);1);0);0;COUNTA($A$1:$A$11);1);MATCH(B$14;OFFSET($A$1;MATCH(B$14;OFFSET($A$1;0;MATCH($A15;$A$1:$K$1;0)-1;COUNTA($A$1:$A$11);1);0);MATCH($A15;$A$1:$K$1;0)-1;COUNTA($A$1:$A$11);1);0));""))
)

Problema acestei căutări este dată de determinarea celei de-a doua părți a coloanei de căutare care este diferită de la coloană la coloană în funcție de poziția căutării primei valori din coloană.

Sfat: Dacă vi se pare o virtute să scrii formule ca cea de mai sus în Excel, aflați că răspunsul este NU. Important este să găsești o soluție elegantă și corectă, nu una în care folosești multe litere.

Dacă doriți să revedeți articolul despre funcția OFFSET() vă rog să consultați articolul: https://valygreavu.com/2017/05/08/excel-functia-offset/

Soluțiile primte, nu în ordine.

Soluția lui George

Voi începe cu soluția lui George (fost student al meu) care mi s-a părut deosebit de suprinzătoare prin simplitate și corectitudinea rezolvării pentru valori unice.  Dezavantajul că nu rezolvă duplicatele, dar mie mi-a plăcut.

George folosește o funcție array pentru transpose-ul matricii inițiale, după care folosește un concatenate cu Match() pentru a obține matricea de valori.

Fișierul poate fi descărcat și analizat la adresa: https://1drv.ms/x/s!ApGubfWFh8Nuq_teh5GWrX7vs2A2QQ

Soluții cu Power Query

PowerQuery devine din ce în ce mai prezent în rezolvarea problemelor de Excel legate de manipulare a datelor. Ca exemplu:

  • Soluția de la Alexandru (din București) a fost bazată pe PowerQuery și corectă pentru valori unice pe coloană.
  • Ciprian (din Iași) a propus o soluție bazată pe formula mea inițială și pe PowerQuery care respectă valorile multiple pe coloană.

Explicațiile lui Ciprian pentru rezolvarea sa:

Câtă vreme nu ai spus de la început că vrei și asta nu am pierdut timp să fac și asta…. am respectat 100% ce ai enunțat în problemă, chiar și la faza cu înregistrările unice :)

Oricum asta cu numele coloanelor e simplă:

în pasul 2, înlocuiești lista cu numele coloanelor în clar {„Z1”, „Z2”, „Z3”, „Z4”, „Z5”, „Z6”, „Z7”, „Z8”, „Z9”, „Z10″}) cu numele TUTUROR coloanelor: Table.ColumnNames(Source)

dacă vrei toate coloanele în afară de prima,  atunci înlocuiești cu Text.Split(Text.AfterDelimiter(Text.Combine(Table.ColumnNames(Source),”,”),”,”,1),”,”)

algoritmul e simplu:

let

//Pas.1 – Preiau datele de intare

Source = Excel.CurrentWorkbook(){[Name=”Table1″]}[Content],

//Pas2. – Opțional – conserv zilele care nu au valori, altfel se pierd la repivotare

#”Replaced Value” = Table.ReplaceValue(Source,null,”0″,Replacer.ReplaceValue,Text.Split(Text.AfterDelimiter(Text.Combine(Table.ColumnNames(Source),”,”),”,”,1),”,”)),

//Pas3. – evident

#”Unpivoted Columns” = Table.UnpivotOtherColumns(#”Replaced Value”, {„Valori/Ziua”}, „Ziua”, „Contor”),

//Pas4. Opțional – … mă deranja numele neconform conținutului :)

#”Renamed Columns” = Table.RenameColumns(#”Unpivoted Columns”,{{„Valori/Ziua”, „Valori”}}),

//Pas5. grupez înregistrările multiple. după dorință se poate renunța și în pivot iei primul, ultimul, minim, max, media, mediana, etc.

#”Grouped Rows” = Table.Group(#”Renamed Columns”, {„Contor”, „Ziua”}, {{„Valori_Combinate”, each Text.Combine(_[Valori],”,”), type text}}),

//Pas6. repivotez datele

#”Pivoted Column” = Table.Pivot(#”Grouped Rows”, List.Distinct(#”Grouped Rows”[Contor]), „Contor”, „Valori_Combinate”),

//Pas7. opțional de două ori: elimin coloana pentru null. 1. Poate fi arătată dacă interesează pe cineva. 2. dacă se renunță la 2 dispare și ea

#”Removed Columns” = Table.RemoveColumns(#”Pivoted Column”,{„0”}),

//Pas8. Opțional pentru că denumirea coloanelor nu permite ordonarea lexicografică, creez o coloană care să poată fi sortată după cum mă aștept

#”Added Custom” = Table.AddColumn(#”Removed Columns”, „Sort”, each Text.Combine({Text.At([Ziua],0),Text.End(Text.Combine({„0”,Text.Middle([Ziua],1)}),2)})),

//Pas9. opțional – sort

#”Sorted Rows” = Table.Sort(#”Added Custom”,{{„Sort”, Order.Ascending}}),

//Pas10. opțional – elimin coloana de sortare

#”Removed Columns1″ = Table.RemoveColumns(#”Sorted Rows”,{„Sort”})

in

#”Removed Columns1″

Practic pentru a obține același lucru ca în formulele din Excel ai nevoie de 3 pași, pentru a aduce valorile multiple 4, iar restul sunt de floricele

Soluția poate fi descărcată și analizată aici: https://1drv.ms/x/s!ApGubfWFh8Nuq_tgh5GWrX7vs2A2QQ

Soluția cu DAX

Am alocat un subcapitol pentru soluția lui Cristian din Timișoara. Asta pentru că folosește DAX (Data Analysis Expressions) în rezolvarea problemei, pe lângă faptul că o rezolvă și cu PowerQuery. Recunosc că m-am simțit puțin încurcat de povestea cu DataModel și limbajul specific:

Data:=VAR __DISTINCT_VALUES_COUNT = DISTINCTCOUNT(‘DAX'[Value])
VAR __MAX_VALUES_TO_SHOW = 10
RETURN
IF(
__DISTINCT_VALUES_COUNT > __MAX_VALUES_TO_SHOW;
CONCATENATE(
CONCATENATEX(
TOPN(__MAX_VALUES_TO_SHOW; VALUES(‘DAX'[Value]); ‘DAX'[Value]; ASC);
‘DAX'[Value];
„, „;
‘DAX'[Value];
ASC
);
„, etc.”
);
CONCATENATEX(VALUES(‘DAX'[Value]); ‘DAX'[Value]; „, „; ‘DAX'[Value]; ASC)
)

Deci cum?! :)

Soluția lui Cristian poate fi descărcată aici: https://1drv.ms/x/s!ApGubfWFh8Nuq_tih5GWrX7vs2A2QQ

Fișierul conține și un mic macro, dar e safe.

Concluzii

Problema rămâne deschisă. Cred că e prea faină ca să nu mai continuăm să căutăm soluții. Folosiți partea de comentarii pentru asta.

Dacă v-au plăcut soluțiile nu ezitați să ne oferiți feedback în partea de comentarii.

Dacă mai aveți probleme faine spre rezolvare nu ezitați să le trimiteți pe mail.

Sper să fie util cuiva.

Blog la WordPress.com.

SUS ↑