Вопрос об интервью в Facebook: Форматирование коллекции времени для вывода времени показа фильма (предпочтительно использование Linq) - PullRequest
4 голосов
/ 16 августа 2010
class TimeObject
{
    DateTime time;
    bool isMatinee;
}

Given: {8:00, 9:30, 11:00, 12:10, 2:00, 4:00, 5:20} -- a collection of TimeObjects

Output: (8:00AM, 9:30, 11:00, 12:10PM, 2:00), 4:00, 5:20 -- return a string, oh and AM/PM should be picked up from localization strings

Caveats: AM/PM only shown for first time, ( ) encloses those elements whose matinee bool was set to true.

Вопрос в том, что мне нужно выяснить, как вывести указанную выше строку.

Я уже говорил, я знал C #, интервьюер был непреклонен, чтобы знать, как это сделать в наименьшем количестве читаемых строк.код, желательно с использованием LINQ.Он сказал, что я могу записать это на консоль, но я должен был помнить, чтобы локализовать AM и PM.

Я, очевидно, создал кучу временных коллекций и дерьма и полностью испортил это.Он утверждает, что это всего лишь несколько строк LINQ.Я пробовал другие вещи, хотя он продолжал направлять меня к LINQ.

Помогите?У какого тела есть идеи?Это действительно мучило меня весь день.

ОБНОВЛЕНИЕ - Я ПОЛУЧИЛ РАБОТУ!Они также попросили меня изменить расстояние {HELLO} -> {HLO}, скажите мин.количество правок / обновлений, которые потребуется, чтобы добраться до последней строки.И есть пчелы, и мед в мире, есть одна королева пчел, единственный способ получить доступ к меду - через королеву.Создайте виртуальный компьютерный мир, который может это поддержать, и скажите, нарушает ли мир нарушения - График , Корневой узел - это Queen Bee, Узлы - это Honey and Bee, Запустите тест BiPartite, чтобы увидеть, если мирв нарушении.

Ответы [ 4 ]

2 голосов
/ 16 августа 2010

[править]
Я уверен, что есть более чистый способ сделать это, но вот что у меня есть. Простая группировка облегчила бы, если бы не ограничения по времени. Я постараюсь придумать другую версию.

var amTimes = times.Where(to => to.time.Hour < 12)
                   .Select((to, i) => new
                   {
                       to.isMatinee,
                       repr = i == 0 ? to.time.ToString("h:mmtt")
                                     : to.time.ToString("h:mm")
                   });
var pmTimes = times.Where(to => to.time.Hour >= 12)
                   .Select((to, i) => new
                   {
                       to.isMatinee,
                       repr = i == 0 ? to.time.ToString("h:mmtt")
                                     : to.time.ToString("h:mm")
                   });
var stimes = amTimes.Concat(pmTimes);
var mats = String.Join(", ", stimes.Where(t => t.isMatinee).Select(t => t.repr));
var nonmats = String.Join(", ", stimes.Where(t => !t.isMatinee).Select(t => t.repr));

var output = string.Format("({0}), {1}", mats, nonmats);

[edit2]
Хорошо, так что это, скорее всего, тот ответ, который искал интервьюер.

var output = String.Join(", ",
    times.Select(to => new
    {
        prefix = to == times.First(t => t.isMatinee) ? "(" : "",
        time = to.time,
        fmt = to.time.Hour < 12
            ? (to == times.First(t => t.time.Hour < 12) ? "h:mmtt" : "h:mm")
            : (to == times.First(t => t.time.Hour >= 12) ? "h:mmtt" : "h:mm"),
        suffix = to == times.Last(t => t.isMatinee) ? ")" : "",
    })
    .Select(x => String.Format("{0}{1}{2}", x.prefix, x.time.ToString(x.fmt), x.suffix)));

Обычно, когда я пишу выражения LINQ, я всегда стараюсь учитывать производительность. Поскольку производительность здесь не является фактором. Это должно быть легче всего писать и следовать (но с ужасной производительностью).

Подход, учитывайте время, способ его форматирования и любой префикс (открытый символ) или суффикс (закрывающий элемент) при печати Пока группировка isMatinee является непрерывной (что я всегда предполагал) с отсортированным временем, это всегда должно работать.

Он имеет префикс только в том случае, если это первый раз в утреннике. Суффикс, если это последний раз, когда утренник. Он должен быть отформатирован с AM / PM, если он впервые в соответствующей группе. Это должно быть очень легко понять.


Если бы речь шла только о группировке утренников, я бы, наверное, сделал это:

var output = String.Join(", ",
    times.GroupBy(to => to.isMatinee, to => to.time.ToString("h:mm"))
         .Select(g => g.Key ? "(" + String.Join(", ", g) + ")"
                            : String.Join(", ", g)));
1 голос
/ 16 августа 2010
bool AMShown = false;
bool PMShown = false;
StringBuilder sb = new StringBuilder();

//assuming it groups with false first:
foreach(var timeObjGrp in collection.GroupBy(p=>p.isMatinee))
{
    if (grpTimeObj.Key) StringBuilder.Append("(");
    foreach (var timeObjItem in timeObjGrp)
    {
        StringBuilder.Append(timeObjItem.time.ToString("h:m"));
        //IsAM should be something like Hours < 12
        if (!AMShown && timeObjItem.time.IsAM)
        {
            StringBuilder.Append("AM");
            AMShown = true;
        }
        if (!PMShown && timeObjItem.time.IsPM)
        {
            StringBuilder.Append("PM");
            PMShown = true;
        }
        StringBuilder.Append(",");
    }
    //here put something to remove last comma
    if (grpTimeObj.Key) StringBuilder.Append(")");
    StringBuilder.Append(",");
}
//here put something to remove last comma

Я не уверен, что достаточно LINQ-иша, но он читается

0 голосов
/ 16 августа 2010

Я бы вряд ли назвал это коротким (и читаемым), но это почти все, по крайней мере, LINQ:


            var outputGroups =
                from item in given
                let needSuffix =
                    object.ReferenceEquals(item, given.FirstOrDefault(to => to.Time.Hour < 12)) ||
                    object.ReferenceEquals(item, given.FirstOrDefault(to => to.Time.Hour >= 12))
                let suffix = needSuffix ? "tt" : string.Empty // could use AM/PM from resources instead of DateTime format string
                let timeFormat = string.Format("H:mm{0}", suffix)
                group item.Time.ToString(timeFormat) by item.IsMatinee into matineeGroup
                orderby matineeGroup.Key descending
                let items = string.Join(", ", matineeGroup.ToArray())
                let format = matineeGroup.Key ? "({0})" : "{0}"
                select string.Format(format, items);

            var result = string.Join(", ", outputGroups.ToArray());

0 голосов
/ 16 августа 2010

Как насчет этого?

var output =
    String.Join(", ",
        from g in given
        orderby g.time
        group g by g.time.Hour < 12 into ggs
        select
            String.Join(", ", ggs.Select((x, n) =>
            {
                var template = n == 0 ? "{0:h:mmtt}" : "{0:h:mm}";
                template = x.isMatinee ? String.Format("({0})", template) : template;
                return String.Format(template, x.time);
            }).ToArray())
    ).Replace("), (", ", ");

(Здесь предполагается, что время указано только для одного дня.) <Ч /> @ halivingston

Чтобы ответить на ваши вопросы:

Q1. Как работает запрос.

  • Внешний String.Join используется, как вы правильно сказали, для объединения всех отдельных форматированных времен в одну строку.

  • Поскольку Linq является функциональным по своей природе, легче вычислять каждый элемент независимо от остальных, поэтому я заключаю скобки в каждое время утренника. Это вводит избыточные скобки вокруг форматированного времени, которые удаляются функцией Replace.

  • Запрос Linq упорядочивает экземпляры TimeObject на time (поскольку мы не знаем, обязательно ли они в порядке, когда мы получаем коллекцию), а затем группирует их по логическому значению, где true - «AM», а false - «PM». Переменная ggs - это группа, которая создается, и в соответствии с моим соглашением я называю ее "группой g".

  • Каждая группа содержит IEnumerable<TimeObject>, который необходимо повторить для построения каждой отформатированной строки. Однако мы должны различать первый элемент и остальные элементы, поэтому нам нужно использовать перегрузку Select, которая обеспечивает элемент и индекс элемента. После этого мы можем создать шаблон String.Format, который будет правильно добавлять AM / PM к первому элементу, а также добавлять скобки к каждому элементу утренника.

  • String.Join снова используется для объединения отдельных элементов в одну строку. В результате запрос Linq возвращает IEnumerable<string> с двумя элементами. (Внешний String.Join превращает их в последнюю строку.)

Q2. Чтобы разрешить время, охватывающее несколько дней, я бы внес следующие изменения:

group g by g.time.Date.AddHours(g.time.Hour < 12 ? 0.0 : 12:00) into ggs

Это позволит сгруппировать любое количество дней, в то же время разделяя AM и PM.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...