Пересечение списка в бритве и добавление разделителя между элементами

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

item1 | item2 | item3

Самый простой способ перебора элементов - с помощью foreach:

@foreach(var item in Model.items){
  <span>@item.Name</span> | 
}

К сожалению, это добавляет дополнительную строку разделителя в конце списка. Есть ли простой способ пропустить эту последнюю разделительную линию?

Ответ 1

Вы можете использовать string.Join:

@Html.Raw(string.Join("|", model.Items.Select(s => string.Format("<span>{0}</span>", s.Name))))

Использование string.Join отменяет необходимость проверки последнего элемента.

Вы можете смешать это с помощью метода Razor @helper для более сложной разметки:

@helper ComplexMarkup(ItemType item)
{ 
    <span>@item.Name</span>
}

@Html.Raw(string.Join("|", model.Items.Select(s => ComplexMarkup(s))))

Вы даже можете создать вспомогательный метод для абстрактного вызова Html.Raw() и string.Join():

public static HtmlString LoopWithSeparator
    (this HtmlHelper helper, string separator, IEnumerable<object> items)
{
    return new HtmlString
          (helper.Raw(string.Join(separator, items)).ToHtmlString());
}

Использование:

@Html.LoopWithSeparator("|",  model.Items.Select(s => ComplexMarkup(s)))

Ответ 2

Не уверен, что это самый простой способ, или если это более элегантный способ, но вы можете сделать что-то вроде:

@foreach ( var item in Model.items){
    <span>@item.Name</span> @(Model.items[Model.items.Count - 1] != item ? "|" : "")
}

Итак, вы в основном проверяете, является ли item последним элементом в списке.

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

Ответ 3

Сохраните переменную счетчика и внутри цикла и проверьте, является ли это последним элементом или нет.

@{ int counter=0; }
@foreach(var item in Model.items){
  counter++;
  <span>@item.Name</span>
  if(counter<Model.Items.Count) 
  {
    @Html.Raw("|")
  } 
}

а короткая версия

@{ int counter=0; }
@foreach(var item in Model.items){
  counter++;
  <span>@item.Name</span> @(counter< Model.items.Count?"|":"")
 } 

Ответ 4

Объединив другие ответы здесь с этой статьей на встроенных шаблонах, я придумал этот вспомогательный метод, который можно поместить в класс расширения

public static HelperResult Join<T>(this IEnumerable<T> list, Func<T, HelperResult> template, Func<T, HelperResult> separator)
{
    var first = true;
    var result = new HelperResult(writer =>
    {
        foreach (var item in list)
        {
            if (first == false)
                separator(item).WriteTo(writer);
            first = false;
            template(item).WriteTo(writer);
        }
    });

    return result;
}

Тогда его можно было бы использовать

@Model.ListOfItems.Join(
    @<a href="@item.Href">
        @item.Name
    </a>, 
    @<text> | </text>)

Это поддерживает html как в элементах, так и в разделителе.