Frage

I have a "Element" class with a "Index" property which is used for sorting a list of elements. When i'm adding elements to the list I want to spread out the new elements evenly according to existing elements in the list.

This means if I have 6 elements and want to add 3 elements the result should look like the image below:

enter image description here

The problem I have with my code (See below) so far is it uses the wrong index, so if I have 2 existing elements and add 9 elements, the last element index is 18 which I don't really understand.

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;
}
War es hilfreich?

Lösung

Divide your original number of elements by the list you want to mix it with. 6/3 + 1=3(every 3rd item will be from list2). Run a loop for(var i = 0; i < list1.Count + list2.Count; i++) Within each loop check if the position of the new list is at the point where you should insert the item from list2 otherwise insert the next item from list1. Here it is as an extension method...

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;
    }
}

Andere Tipps

Aren't you looking for temporal ordering? This suggests to use KeyCollection.

How to insert as first element in dictionary?

The InsertItem method looks interesting.

I develop it like this:

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;
    }
}

And here just a console code to test the output:

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();
        }
    }
}

Sample output

output

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top