2013-12-05 4 views
4

У меня есть класс «Элемент» со свойством «Index», которое используется для сортировки списка элементов. Когда я добавляю элементы в список, я хочу равномерно распределить новые элементы в соответствии с существующими элементами в списке.Добавить элементы равномерно в список

Это означает, что если у меня есть 6 элементов и хотите добавить 3 элемента результат должен выглядеть как на картинке ниже:

enter image description here

У меня есть проблема с моим кодом (смотрите ниже) до сих пор является его использует неправильный индекс, поэтому, если у меня есть 2 существующих элемента и добавьте 9 элементов, последний индекс элемента - 18, который я действительно не понимаю.

public List<Element> AddElements() 
{ 
    // The elements are inserted before this 
    List<Element> existingElements = new List<Element>(); 
    List<Element> elementsToAdd = new List<Element>(); 

    int elementsLeft = 1; 

    foreach (Element element in elementsToAdd) 
    { 
     // Generate the next index 
     int nextIndex = 1; 

     // Only proceed if any elements exists 
     if (existingElements.Count > 0) 
     { 
      // divisonResult = 12/4 = 3 
      double divisonResult = Math.Floor(Convert.ToDouble(existingElements.Count)/Convert.ToDouble(elementsToAdd.Count)); 

      // modulusResult = 12 % 2 = 0 
      double modulusResult = Convert.ToDouble(existingElements.Count) % Convert.ToDouble(elementsToAdd.Count); 

      // NextPosition = (3 + 1) * 1 = 4 
      // NextPosition = (3 + 1) * 2 = 8 
      // NextPosition = (3 + 1) * 3 = 12 
      // NextPosition = (3 + 1) * 4 = 16 
      if (modulusResult <= 0 && elementsToAdd.Count > 1) 
       nextIndex = Convert.ToInt16(divisonResult) * elementsLeft; 
      else 
       nextIndex = (Convert.ToInt16(divisonResult) + 1) * elementsLeft; 

      elementsLeft++; 

      // Move existing elements 
      var elementsToBeMoved = existingElements.Where(elementQuery => elementQuery.Index >= nextIndex); 

      foreach (Element elementToBeMoved in elementsToBeMoved) 
      { 
       elementToBeMoved.Index++; 
      } 
     } 

     // Add element to existing elements 
     existingElements.Add(new Element { Index = nextIndex }); 
    } 

    // Return new list 
    return existingElements; 
} 
+1

Что это? Не будучи легкомысленным, я просто думаю, что запрос интересен, но я не вижу, что вы будете использовать его немедленно. –

+0

Это звучит неплохо. Вы получите ужасную производительность при вставках в List, потому что она должна скопировать все элементы после того, который вы вставляете в первую очередь. Если ваш список длиннее нескольких элементов, это может быть узким местом. Какую проблему ты пытаешься решить? Вероятно, есть лучший способ сделать это, чем равномерно распределить элементы в списке ... – Luaan

+0

'Convert.ToDouble (existingElements.Count)/Convert.ToDouble (elementsToAdd.Count)' это просто: '1.0 * existingElements.Count/elementsToAdd.Count'. Или, может быть, использовать '(double)' cast. Почему все люди настаивают на использовании машин «Convert» для таких простых вещей: 0 – BartoszKP

ответ

1

Разделите свое исходное количество элементов по списку, с которым хотите его смешивать. 6/3 + 1 = 3 (каждый третий элемент будет из списка2). Запустите цикл для (var i = 0; i < list1.Count + list2.Count; i ++). В каждом цикле проверьте, находится ли позиция нового списка в точке, где вы должны вставить элемент из списка2, иначе вставьте следующий элемент из списка1. Здесь это как метод расширения ...

class Program 
{ 
    static void Main(string[] args) 
    { 
     var existingElements = new List<int> { 1, 2, 3, 4, 5, 6 }; 
     var elementsToAdd = new List<int> { 100, 101, 102 }; 
     existingElements = existingElements.Mix(elementsToAdd).ToList(); 
     Console.WriteLine(String.Join(", ", existingElements)); 
     Console.ReadKey(); 
    } 
} 

public static class ExtensionMethods 
{ 
    public static IEnumerable<T> Mix<T>(this IEnumerable<T> source, IEnumerable<T> mix) 
    { 
     var list1 = source.ToArray(); 
     var list2 = mix.ToArray(); 
     var total = list1.Count() + list2.Count(); 
     var skip = (list1.Count()/list2.Count()) + 1; 
     var count1 = 0; 
     var count2 = 0; 
     var finalList = new List<T>(); 

     for (var i = 0; i < total; i++) 
     { 
      var count = i + 1; 
      if (count % skip == 0) 
      { 
       finalList.Add(list2[count2]); 
       count2++; 
      } 
      else 
      { 
       finalList.Add(list1[count1]); 
       count1++; 
      } 
     } 

     return finalList; 
    } 
} 
+0

Спасибо, я помету ваш ответ как принятый, так как он, вероятно, самый лучший, который я найду. С другой стороны, как Visual Studio знала, где установить точки останова только от меня, копируя код? – Dumpen

+0

Ваши точки останова должны хорошо накладываться на то, что я написал, и я думаю, что VS слегка приспосабливает их при вставке. –

0

Я развиваю это так:

public static class IEnumerableExtender 
{ 
    public static IEnumerable<T> Mix<T>(this IEnumerable<T> first, IEnumerable<T> second) 
    { 
     var firstCount = first.Count(); 
     var secondCount = second.Count(); 

     // it is important that `first` is equal or larger 
     // than `second`, if it is not, we swap 
     if (firstCount < secondCount) 
     { 
      var a = first; 
      first = second; 
      second = a; 
      firstCount = first.Count(); 
      secondCount = second.Count(); 
     } 

     // at every `N` number of elements we will insert 
     // one from the `second` list 
     var insertAtEvery = Math.Floor(firstCount/(double)secondCount) + 1; 

     int totalLength = firstCount + secondCount; 

     var listResult = new List<T>(totalLength); 

     for (int i = 0, x = 0, y = 0; i < totalLength; ++i) 
     { 
      // if it is time to insert an element from `second` 
      // and there is still something to be inserted 
      if ((i % insertAtEvery) == 0 && y < secondCount) 
      { 
       // insert and move the index from the `second` 
       listResult.Add(second.ElementAt(y++)); 
      } 
      else 
      { 
       // insert and move the index from the `first` 
       listResult.Add(first.ElementAt(x++)); 
      } 
     } 

     return listResult; 
    } 
} 

И вот только код консоли, чтобы проверить результат:

public class Program 
{ 
    static void Main(string[] args) 
    { 
     int size1, size2; 

     while (true) 
     { 
      Console.Write("Size of list #1: "); 
      int.TryParse(Console.ReadLine(), out size1); 

      if (size1 <= 0) 
       break; 

      Console.Write("Size of list #2: "); 
      int.TryParse(Console.ReadLine(), out size2); 

      if (size2 <= 0) 
       break; 

      var list1 = Enumerable.Range(0, size1).Select(o => '.').ToList(); 
      var list2 = Enumerable.Range(0, size2).Select(o => '#').ToList(); 

      var result = list1.Mix(list2); 

      Console.WriteLine(String.Join(" ", result)); 
      Console.WriteLine(); 
     } 
    } 
} 

Пример вывода

output

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