Менее - подробный способ обработать первичную обработку через foreach?

Я часто делаю следующий встречный индексом беспорядок в цикле foreach узнавать, нахожусь ли я на первом элементе или нет. Есть ли более изящный способ сделать это в C#, чем-то вроде if(this.foreach.Pass == 1) и т.д.?

int index = 0;
foreach (var websitePage in websitePages) {
    if(index == 0)
        classAttributePart = " class=\"first\"";
    sb.AppendLine(String.Format("<li" + classAttributePart + ">" + 
        "<a href=\"{0}\">{1}</a></li>", 
        websitePage.GetFileName(), websitePage.Title));
    index++;
}
22
задан Tomas Petricek 4 September 2011 в 23:55
поделиться

12 ответов

Другой подход - признать, что «некрасивая часть» должна быть где-то реализована, и предоставить абстракцию, которая скрывает «некрасивую часть», чтобы вам не приходилось повторять ее в нескольких местах и ​​можно было сосредоточиться на конкретном алгоритме. . Это можно сделать с помощью лямбда-выражений C # (или с помощью анонимных делегатов C # 2.0, если вы ограничены .NET 2.0):

void ForEachWithFirst<T>(IEnumerable<T> en, 
     Action<T> firstRun, Action<T> nextRun) {
  bool first = true;
  foreach(var e in en) {
    if (first) { first = false; firstRun(e); } else nextRun(e);
  }
}

Теперь вы можете использовать этот многократно используемый метод для реализации своего алгоритма следующим образом:

ForEachWithFirst(websitePages,
  (wp => sb.AppendLine(String.Format("<li class=\"first\">" +
         "<a href=\"{0}\">{1}</a></li>", wp.GetFileName(), wp.Title)))
  (wp => sb.AppendLine(String.Format("<li>" + 
         "<a href=\"{0}\">{1}</a></li>", wp.GetFileName(), wp.Title))) );

Вы можете разработать абстракция по-разному в зависимости от точного повторяющегося узора. Хорошо то, что - благодаря лямбда-выражению - структура абстракции полностью зависит от вас.

13
ответ дан 29 November 2019 в 04:33
поделиться

Чуть менее многословно:

string classAttributePart = " class=\"first\"";
foreach (var websitePage in websitePages)
{
    sb.AppendLine(String.Format("<li" + classAttributePart + "><a href=\"{0}\">{1}</a></li>", websitePage.GetFileName(), websitePage.Title));
    classAttributePart = string.Empty;
}

Если вы используете .NET 3.5, вы можете использовать перегрузку Select, которая дает вам индекс, и проверить это. Тогда вам также не понадобится StringBuilder. Вот код для этого:

string[] s = websitePages.Select((websitePage, i) =>
        String.Format("<li{0}><a href=\"{1}\">{2}</a></li>\n",
                      i == 0 ? " class=\"first\"" : "",
                      websitePage.GetFileName(),
                      websitePage.Title)).ToArray();

string result = string.Join("", s);

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

11
ответ дан 29 November 2019 в 04:33
поделиться

Вы можете использовать цикл for вместо цикла foreach. В этом случае ваш цикл for мог бы начинать свой индекс с 1, и вы могли бы выполнять первый элемент вне цикла, если длина больше 0.

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

4
ответ дан 29 November 2019 в 04:33
поделиться
if (websitePages.IndexOf(websitePage) == 0)
    classAttributePart = " class=\"last\"";

Это может быть более элегантно, но, вероятно, будет менее производительно, поскольку придется проверять индекс каждого элемента.

4
ответ дан 29 November 2019 в 04:33
поделиться

login _ required предназначен для обращения к ракурсу, вызываемому, не включающему (), и просмотра исходного кода:

http://code.djangoproject.com/browser/django/tags/releases/1.1.1/django/conf/urls/defaults.py#L9

- Я не думаю, что существует простой способ использования стандартного (или даже пользовательского) login _ обязательного с include () для достижения желаемого.

Написав это, я думаю, что разумным подходом было бы использовать некоторое «требуемое промежуточное программное обеспечение», как это: http://www.djangosnippets.org/snippets/1179/ и забыть о украшении urls в urls.py.

-121--1229802-

Посмотрите на Blackbird . Это экранный javascript-журнал/отладчик. В коде следует поместить log.debug (объект), и он будет выведен в обозреватель в наложении div. Я не знаю, работает ли это, если просто передать объект, но очевидно, что у вас уже есть object.dumpvars () уже отработан.

-121--4667560-

Это может быть немного лучше

bool doInit = true;
foreach (var websitePage in websitePages)
{
    if (doInit)
    {
        classAttributePart = " class=\"first\"";
        doInit = false;
    }
    sb.AppendLine(String.Format("<li" + classAttributePart + "><a href=\"{0}\">{1}</a></li>", websitePage.GetFileName(), websitePage.Title));
}

Я в конечном итоге делаю такого рода вещи тоже, и это меня также беспокоит.

4
ответ дан 29 November 2019 в 04:33
поделиться

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

var iter = websitePages.GetEnumerator();
iter.MoveNext();
//Do stuff with the first element
do {
    var websitePage = iter.Current;
    //For each element (including the first)...
} while (iter.MoveNext());
1
ответ дан 29 November 2019 в 04:33
поделиться

Вы можете сделать это перед циклом foreach, если вы делаете это только для первого индекса.

2
ответ дан 29 November 2019 в 04:33
поделиться

Если вас интересует только первый элемент, лучший (в смысле наиболее читабельный) способ - использовать LINQ, чтобы узнать, какой элемент является первым. Например, так:

var first = collection.First();
// do something with first element
....
foreach(var item in collection){
    // do whatever you need with every element
    ....
    if(item==first){
        // and you can still do special processing here provided there are no duplicates
    }
}

Если вам нужно числовое значение индекса или непервый индекс, вы всегда можете сделать

foreach (var pair in collection.Select((item,index)=>new{item,index}))
{
    // do whatever you need with every element
    ....
    if (pair.index == 5)
    {
        // special processing for 5-th element. If you need to do this, your design is bad bad bad
    }
}

PS И самый лучший способ - использовать for-петлю. Используйте foreach только если for недоступен (т.е. коллекция является IEnumerable, а не списком или чем-то еще)

2
ответ дан 29 November 2019 в 04:33
поделиться

Другой подход заключается в использовании первого селектора jQuery для установки класса вместо кода на стороне сервера.

$(document).ready(function(){ 
     $("#yourListId li:first").addClass("first");
}
3
ответ дан 29 November 2019 в 04:33
поделиться

Как любит говорить мой отец: «Используйте правильный инструмент для работы».

В этом случае посмотрите, что должен делать ваш цикл.

  • Если что-то можно сделать вне цикла, переместите его, и вы можете использовать foreach.
  • Если вам нужно обработать сложную комбинацию случаев, вы можете рассмотреть возможность использования другого шаблона (например, шаблона состояния или другого наиболее подходящего) для того, что вы хотите сделать внутри цикла, и в этом случае вы выбираете конструкцию цикла, которая имеет наибольший смысл в данный момент.
  • Если ваш цикл зависит от возможности извлечь индекс итерации, чтобы передать его в другое место, то, возможно, цикл for может быть лучшим выбором.

В противном случае, отвечая на ваш вопрос, не может быть простого неполнотного средства для определения индекса элемента списка при доступе к нему в цикле foreach.

0
ответ дан 29 November 2019 в 04:33
поделиться

ОКОНЧАТЕЛЬНОЕ ОБНОВЛЕНИЕ: Две библиотеки кажутся примерно эквивалентными. Zlib дает примерно на 20% лучшее сжатие, в то время как скорость декодирования LZO примерно в два раза быстрее, но производительность любого из них очень мала, почти ничтожна. Это мой окончательный ответ. Спасибо за все остальные ответы и комментарии!

ОБНОВЛЕНИЕ: После внедрения сжатия LZO и заметного улучшения производительности, очевидно, что в ударе по производительности виноват мой собственный код (возможно значительное увеличение количества сценариев на пакет, таким образом, мой эффект «интерпретатор» становится намного больше.) Я хотел бы смиренно извиниться за то, что взбесился переложить вину, и я надеюсь, что никаких обид не будет. Я сделаю некоторые профилирование, и тогда, возможно, я смогу получить некоторые цифры, которые будут более полезны для кого-то еще.

ORIGINAL POST:

Хорошо, я наконец-то начал писать код для этого. Я начал со Злиба, вот первые мои выводы.

Сжатие Злиба безумно велико. Это надежно сокращает пакеты, скажем, 8,5 kib до, скажем, 750 байт или менее, даже при сжатии с Z_BEST_SPEED (вместо Z_DEFAULT_COMPRESSION.) Время сжатия также довольно хорошее.

Однако я понятия не имел, что скорость декомпрессии чего-либо может быть даже таким плохим. У меня нет фактических чисел, но это должно занять хотя бы 1/8 секунды на пакет! (Core2Duo T550 при 1,83 ГГц.) Совершенно неприемлемо.

Из того, что я слышал, LZMA является компромиссом худшей производительности по сравнению с лучшим сжатием по сравнению с Zlib. Поскольку сжатие Zlib уже перегружено, а его производительность уже невероятно плоха, LZMA скрывается от невидимого пока вида.

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

-121--4349330-

Если вы читаете такое выражение

if ('string1') or ('string2') or ('string3' in line):

Проблема становится очевидной. Что произойдет, так это то, что «string1» вычисляется как True, так что остальное выражение является коротким.

Длинная рука, чтобы написать это это

if 'string1' in line or 'string2' in line or 'string3' in line:

Который является бит повторяется, так что в этом случае лучше использовать любой () , как в ответ Игнасио

-121--3047926-

В этом примере можно избавиться от проверки индекса таким образом.

foreach (var websitePage in websitePages) 
{ 
    classAttributePart =  classAttributePart ?? " class=\"first\""; 
    sb.AppendLine(String.Format("<li" + classAttributePart + "><a href=\"{0}\">{1}</a></li>", websitePage.GetFileName(), websitePage.Title)); 
} 

Для выполнения такого рода задач лучше проверить результирующую переменную данных. В этом случае он проверяет значение null строки classAttriburePart и добавляет начальное значение.

0
ответ дан 29 November 2019 в 04:33
поделиться
public static class ExtenstionMethods
{
    public static IEnumerable<KeyValuePair<Int32, T>> Indexed<T>(this IEnumerable<T> collection)
    {
        Int32 index = 0;

        foreach (var value in collection)
        {
            yield return new KeyValuePair<Int32, T>(index, value);
            ++index;
        }
    }
}

foreach (var iter in websitePages.Indexed())
{
    var websitePage = iter.Value;
    if(iter.Key == 0) classAttributePart = " class=\"first\"";
    sb.AppendLine(String.Format("<li" + classAttributePart + "><a href=\"{0}\">{1}</a></li>", websitePage.GetFileName(), websitePage.Title));
}
0
ответ дан 29 November 2019 в 04:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: