将元素平均添加到列表中

4
我有一个“Element”类,其中包含“Index”属性,用于对元素列表进行排序。当我向列表添加元素时,我希望根据列表中已有的元素均匀地分散新元素。
这意味着如果我有6个元素并想要添加3个元素,则结果应如下图所示:
[图片]
我目前代码的问题在于它使用了错误的索引,因此如果我有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
这是用来做什么的?我并不是在开玩笑,我只是觉得这个请求很有趣,但我立刻看不出你会用它来做什么。 - Adam Houldsworth
那听起来像是一个不好的想法。在List中插入操作的性能将非常糟糕,因为它必须先复制插入位置之后所有的项。如果列表长度超过几个项目,它可能会成为瓶颈。你试图解决什么问题?可能有比均匀地分散项在列表中更好的方法... - Luaan
Convert.ToDouble(existingElements.Count) / Convert.ToDouble(elementsToAdd.Count) 转换为 1.0 * existingElements.Count / elementsToAdd.Count。或者可以使用 (double) 强制转换。为什么所有人都坚持使用 Convert 机制来处理这样简单的事情呢? ;0 - BartoszKP
Adam:它用于插入不同类型的元素,其中一种类型的元素需要均匀分布。更具体地说,它是我公司广告系统中的一个功能 :-) Luaan:我正在尝试将它们均匀分布,这就是问题所在。这是我正在尝试实现的一个特性。 - Dumpen
看看我的建议。它可能需要重新开始,但总体上你可能会得到更整洁的东西。 - Francis Ducharme
3个回答

1

将原始元素数量除以要混合的列表。6/3 + 1 = 3(每3个项目中会有一个来自list2)。运行循环 for(var i = 0; i < list1.Count + list2.Count; i++)。在每个循环中检查新列表的位置是否达到了应该插入list2项的位置,否则插入list1的下一项。以下是扩展方法示例...

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

谢谢,我会将您的答案标记为已接受,因为这可能是我能找到的最好的答案。顺便问一下,Visual Studio 是如何从我复制的代码中知道在哪里设置断点的呢? - Dumpen
你的断点必须与我编写的代码完美重合,我认为当你粘贴时,VS会稍微调整它们。 - Rush Frisby

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


0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接