2015-11-14 1 views
-1

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

У меня день имя класса, как показано ниже

public class Day 
{ 
    public String Name{get; set;} 
    public bool IsActive{get; set;} 
} 

У меня есть список , который содержит все дни. Теперь я хочу удалить элемент из начала, а также из конца, если начальный или конечный элемент в списке i.e Day заполняет это условие: Day.IsActive == true.

Я хочу, чтобы извлекать элемент из списка и от начала и конца (чтобы сделать его более эффективным) в то же время, до тех пор пока в точке, где список не имеет элемент в начале и в конце, где Day.IsActive == true

Так случаи может быть

  1. активной неактивное неактивными-активный-активный
  2. активный-активный
  3. активной неактивное
  4. неактивны-неакт ив

Это то, что я придумал, что решает проблему, но есть лучший способ, что я могу сделать

public IList<Day> RemoveDays(IList<Day> days) 
     { 
      while (days.Count > 0 && (days.First().IsActive || days.Last().IsActive)) 
      { 
       if(days.First().IsActive) 
        days.RemoveAt(0); 
       if (days.Count > 0 && days.Last().IsActive) 
        days.RemoveAt(days.Count - 1); 
       return RemoveDays(days); 
      } 

      return days; 
     } 
+0

Значит, вы хотите удалить все элементы IsActive == true? –

+0

@ KosalaW не обязательно, следуя логике OP, она может быть «активной» - неактивной - активной - неактивной - активной ». который приведет к 'inactive - active - inactive' – Jonesopolis

+0

@Jonesopolis: Ok Спасибо. Понял. Дай мне подумать. –

ответ

0

Это то, что я придумал, надеюсь, что это поможет другим.

public IList<Day> RemoveDays(IList<Day> days) 
{ 
    while (true) 
    { 
     if (days.Count <= 0 || !(days.First().IsActive || days.Last().IsActive)) return days; 
     if (days.First().IsActive) 
      days.RemoveAt(0); 
     if (days.Count > 0 && days.Last().IsActive) 
      days.RemoveAt(days.Count - 1); 
    } 
} 
+0

. Простое решение LINQ: 'var newlist = days.SkipWhile (d => d.IsActive) .Reverse(). SkipWhile (d => d.IsActive) .Reverse(). ToList() ; ' –

+0

@JimMischel благодарю вас за это. Я отлично работаю – King

0

Попробуйте

  while (list.Count > 2) 
      { 
       if (list[0].IsActive || list[list.Count - 1].IsActive) 
       { 
        list.RemoveAt(list.Count - 1); 
        list.RemoveAt(0); 
       } 
       else 
        break; 
      } 

Update 1:

Теперь я хочу удалить элемент от начала, а также от конца, если начальный или конечный элемент в списке i.e Day заполняет это условие: Day.IsActive == true.

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

Если нет, то используйте следующую

  while (list.Count > 2) 
      { 
       if (list[0].IsActive && list[list.Count - 1].IsActive) 
       { 
        list.RemoveAt(list.Count - 1); 
        list.RemoveAt(0); 
       } 
       else 
        break; 
      } 
+0

. Этот код удаляет элемент из начала и конца, если либо начало, либо конец, либо оба имеют IsActive = true. Но что, если начало или конец не IsActive = true. Он все равно удалит его. Цель этой функции - удалить элемент из начала и конца с помощью IsActive = true. – King

+0

@King Обновлен мой ответ. – SILENT

0

Это решение, которое это делает. Я предположил, рекурсивная часть задачи требуется, так это делается рекурсивно вместо итерационного подхода:

class Program 
{ 
    public static IList<Day> ClearList(IList<Day> days) 
    { 
     return days.First().IsActive && days.Last().IsActive ? 
      ClearList((days.Skip(1).Take(days.Count - 2)).ToList()) : 
      days; 
    } 

    static void Main(string[] args) 
    { 
     List<Day> days = new List<Day> 
     { 
      new Day {IsActive = true, Name="M" }, 
      new Day {IsActive = true, Name="T" }, 
      new Day {IsActive = false, Name="W" }, 
      new Day {IsActive = false, Name="Th" }, 
      new Day {IsActive = true, Name="F" }, 
      new Day {IsActive = true, Name="St" }, 
      new Day {IsActive = true, Name="Su" }, 
     }; 

     var cleared = ClearList(days); 
    } 
} 

Внутри метода ClearList первые есть проверка, если оба конца активен. Если так, пропустите сначала, как все остальные, кроме последнего, и снова передайте его методу ClearList. В противном случае верните коллекцию.

+0

Но что происходит в соответствии с этим кодом, если в начале или в конце есть только IsActive или оба или ни одно из них. – King

+0

Не совсем. Обратите внимание, что у вас есть условие && (и). Таким образом, код будет запускаться, если 'days.First(). IsActive' и' days.Last(). IsActive' в противном случае он вернет коллекцию, потому что по крайней мере на условиях это неверно. Помните, что с booleans 'day.IsActive' эквивалентно' day.IsActive == true'. – PiotrWolkowski

+0

О, я не заметил, что у вас есть &&, извините, но что произойдет, только в начале или в конце. Он не удалит его. Я просто добавил несколько случаев в моем вопросе для большей ясности. – King

0

Как насчет рекурсивного подхода Linq?

public static List<Day> Check(List<Day> days) { 
    if (days.Count < 2) 
     return days; 
    else if (days.First().IsActive || days.Last().IsActive) { 
     var daysInBetween = days.Take(days.Count - 1).Skip(1); 
     return Check(daysInBetween); 
    } 
    else 
     return days; 
} 
+0

Этот код удалит элемент из начала и конца, если либо начало, либо конец, либо оба имеют IsActive = true. Но что, если начало или конец не IsActive = true, оно все равно удалит его. заключается в том, чтобы удалить элемент из начала и конца с помощью IsActive = true. Единственная причина, по которой я хочу проверить запуск и конец в одно и то же время, - сделать его более эффективным. – King

+0

Честно говоря, я нахожу ваш комментарий парадоксальным для того, что вы объяснили. , эффективность, достигаемая с помощью такого рода настроек, обычно довольно незначительна. – Rsh

+0

Я только что отредактировал вопрос с моей реализацией, которая решает проблему, но есть ли лучший способ сделать это. – King

0

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

Поскольку удаление с фронта - это операция O (n) (то есть, она копирует каждый элемент в списке), возможно, самый быстрый способ сделать это - удалить активные элементы с конца, а затем удалить с фронта :

while (theList.Count > 0 && theList[theList.Count-1].IsActive) 
{ 
    theList.RemoveAt(theList.Count-1); 
} 

Теперь определите, сколько нужно удалить с фронта.

int ix = 0; 
while (theList[ix].IsActive) 
{ 
    ++ix; 
} 

// copy remaining items to the front 
int dest = 0; 
if (ix > 0) 
{ 
    for (int i = ix; i < theList.Count-1; ++i) 
    { 
     theList[dest] = theList[i]; 
     ++dest; 
    } 
    // and remove the last ix items from the end 
    while (ix > 0) 
    { 
     theList.RemoveAt(theList.Count-1); 
     --ix; 
    } 
} 

Это делает операцию на месте. Если все в порядке с созданием нового списка, то это намного проще:

int lastItem = theList.Count-1; 
while (theList.Count > 0 && theList[lastItem].IsActive) 
{ 
    lastItem = lastItem - 1; 
} 

int firstItem = 0; 
while (theList[firstItem].IsActive) 
{ 
    ++firstItem; 
} 

// copy items to create a new list 
theList = theList.Skip(firstItem) 
    .Take(lastItem - firstItem) 
    .ToList(); 
+0

Я просто обновил свой вопрос в нескольких случаях. будет действовать как функция Trim, используемая для строки для удаления пробелов от начала и до конца, если таковая имеется. Причина, по которой я хочу смотреть как в начало, так и в конец, заключается в том, чтобы сделать ее более эффективной ficient – King

+0

@King: см. мой обновленный ответ. Нет существенного увеличения производительности, если смотреть на начало и конец в одно и то же время. –

+0

Спасибо, что нашли время. Я проведу несколько тестов. – King

Смежные вопросы