JS Basics подготовка за изпит 01.04.2015 - Задача 4
Днес присъствах на подготовката за изпит, която се проведе, и ми направи впечатление обсъждането около 4-та задача.
Задачата беше All that luggage от https://judge.softuni.bg/Contests/56/JavaScript-Basics-9-January-2015
Направи ми впечатление, че се кара малко на output driven development. Като ще трябва да изкараме един тип обект и директно се почва да се пълни такъв обект, пък после че трябва да се сортира - голяма работа :)
Накрая увиснахме с обект, който няма консистентни пропъртита. Единият има пропърти clothes, другият - banana... :) Ходи ги сортирай.
Някой колега даде идея да се вкарат тези "багажи" в масив, а после да се изтрие квадратната скоба. Това би проработило, пак с известни хакове ще се сортират ключовете, но поне сортирането по килограми ще е по-лесно. За щастие нищо във входа не съдържа квадратни скоби и един стринг риплейс ще свърши работа. Аз не го намирам за много правилен вариант.
Това, което предлагам аз е да се пълни колекцията с туристи и багажи в удобен за програмиста начин, а не в удобен за изхода начин.
Една колекция, която съдържа обекти от следния тип
ИмеНаТуриста: ...
Багажи: {{нова колекция}}
ИмеНаБагажа: ...
Тегло: ...
Чупливо: ...
Тип: ...
НачинНаТранспорт: ...
Това какво предимство ни дава? Можем да сортираме масив от обекти, по common property. Т.е. по ключ, който съществува във всеки един обект. А ако имаме ИмеНаБагажа и Тегло във всеки обект в колекцията с багажи, много лесно можем да сортираме тази колекция/масив.
И когато стане време да аутпутнем, просто ще превърнем нашия масив, в такъв обект какъвто го искат за изхода и ще го принтираме.
Прилагам едно решение, което скалъпих преди малко, може би не е най-оптиизираното, но имплементира тази идея. Със сигурност някои if-ове и цикли имат и по-хитър начин да се направят. Решението без коментарите е около 80 реда. Авторското е 50 реда, така че не казвам, че е по-кратко, но е reusable.
Използвам и един трик - нашия масив от багажи си има ключове "ИмеНаБагажа" и "Тегло", точно един от двата ключа, може да бъде критерий за сортиране. Така че директно взет от user input-а този критерий се слага във функцията за сортиране и се сортират. Няма нужда от switch/case. Има само един IF който проверява ако е "strict" да не прави нищо.
Позволих си да напиша целия този пост с идеята да дам хинт да се работи не по подхода - какъвто ще е изхода да тръгнем от него, а така да си нагласим нещата, че да са ни удобни за работа. Особено когато трябва да приложим сет от операции върху нещо голямо. Изходът винаги е трудната част в judge-а, но не трябва работата ни да се върти около него. Той се наглася все някак накрая :)
Ето го решението с коментари: http://pastebin.com/URpMje26
Успех на изпита.
По принцип е неправилно да работиш с обекти, които нямат common keys. Уж два туриста, ама единия има пропърти ябълки, пък другия картофи? :) Това си плаче да бъде под ключа name, а не самото то да е име на ключ.
Ако се ползва фнукционалния форийч в js ще се избегне collection[k]["possessions"][p]["name"];
Де факто
collection.forEach(function(tourist) {
// tourist е един обект вече
tourist.possession.forEach(function(posssession) {
// possession ти е един обект с багажи. Съответно posession.name е това collection[k]["possessions"][p]["name"];
});
});
Аз напълно разбирам каква е идеята на задачата, той изходът нарочно е такъв, но ако примерно пиша един web service и трябва да изплюя json като изхода, който искат, и го пиша на произволен език (C#, Java...) никога няма да се забъркам с някакъв динамичен обект, и през целия апликейшън да го нося такъв. Според мен това е по error-prone.
Ти поне си учил ООП. Мислиш ли, че е error-prone да си дефинираш class Tourist и class Luggage? Двете имат следното
class Tourist
{
public string Name;
public List<Luggage> Luggages;
}
class Luggage
{
public string Name;
public double Weight;
public string Type;
public string TransferredWith
}
Структурата с която работиш е var collection = new List<Tourist>();
От ООП гледна точка е по-правилно да, но след като се иска да имаме обект на изхода по-логичното е да се работи така, както се очаква. Шефа като ти каже, че иска в такъв формат данните ти може да пробваш да го убедиш, че е идиот, но в крайна сметка трябва да се съобразиш с изискването. И в случая, с цел да е по-правилно моделирането отдолу, нещата се усложняват - пак трябва да сортираш масиви и трябва да ги правиш на обекти.
collection[k]["possessions"][p]["name"] го копирах от твоя код, не си успял да го избегнеш в проверките по-горе в кода. Аз лично имам доста проблеми при подобни ситуации, винаги губя много време да се ориентирам кое какво е.
result[tourist.name][possesion.luggagename] - пак не е много приятно, защото на всеки ключ достъпваш някакви пропъртита.
Това, което имам предвид е, че повечето хора, включително аз, трудно следят лесно толкова на брой променливи и вероятността да се допусне грешка (която се открива и по-трудно) е по-голяма.