如何在C#中动态添加数组的索引值?

时间:2019-09-05 17:19:44

标签: c# arrays

我有一个数组,其中必须将前两个最小值相加,因此结果必须与下一个最小值相加,依此类推,直到到达数组的末尾以给出最终的总数。

但是,如何动态修改方法/函数,因此,如果值发生变化并且我在数组中有6个vehicles和6个specs值,则方法/函数合计的返回不会仅限4个索引。

数组值未排序,因此要添加第一个最小值,必须对其进行排序。一旦完成,它将添加新数组的值。

这是我尝试过的:

public static int vehicles = 4;
public static int[] specs = new int[] { 40, 8, 16, 6 };

public static int time(int vehicles, int[] specs)
{
    int newValue = 0;

    for (int i = 1; i < vehicles; i++)
    {
        newValue = specs[i];
        int j = i;

        while (j > 0 && specs[j - 1] > newValue)
        {
            specs[j] = specs[j - 1];
            j--;
        }
        specs[j] = newValue;
    }

    // How can I dynamically change this below:
    int result1 = specs[0] + specs[1];
    int result2 = result1 + specs[2];
    int result3 = result2 + specs[3];
    int total = result1 + result2 + result3;

    return total; // Returns 114
}

这是它的工作原理:

4, [40, 8, 16, 6] = 14 --> [40, 14, 16] = 30 --> [40, 30] = 70 ==>> 14 + 30 + 70 = 114
6, [62, 14, 2, 6, 28, 41 ] = 8 --> [62, 14, 8, 28, 41 ] --> 22 [62, 22, 28, 41 ] --> 50 
   [62, 50, 41 ] --> 91 [62, 91 ] --> 153 ==> 8 + 22 + 50 + 91 + 153 = 324

5 个答案:

答案 0 :(得分:1)

首先,如果由于某些奇怪的原因而不受限于使用数组,请使用List<int>,这样会使您的生活更轻松。

List<int> integers = { 14, 6, 12, 8 };

integers.Sort();

integers.Reverse();

while( integers.Count > 1 )
{
    int i = integers[integers.Count - 1];
    int j = integers[integers.Count - 2];
    integers[integers.Count - 2] = i + j;
    integers.RemoveAt(integers.Count - 1);
}

var result = integers[0];

P.S .:可以很容易地对其进行修改以在阵列版本上运行,您不能RemoveAt()从阵列上使用,但是可以单独维护lastValidIndex。

答案 1 :(得分:1)

我会使用Linq。

Enumerable.Range(2, specs.Length - 1)
    .Select(i => specs
        .Take(i)
        .Sum())
    .Sum();

说明:

  1. 我们采用的范围从2开始,以specs.Length结尾。
  2. 我们将i的前specs个值相加,其中i是该范围内的当前值。
  3. 所有这些总和之后,我们也将它们加起来。

要了解有关linq的更多信息,请启动here

仅当值已经排序时,此代码才有效。
如果要使用linq对值进行排序,则应使用以下代码:

IEnumerable<int> sorted = specs.OrderBy(x => x);

Enumerable.Range(2, sorted.Count() - 1)
    .Select(i => sorted
        .Take(i)
        .Sum())
    .Sum();

OrderBy函数需要知道如何获取用于比较数组值的值。由于数组值,我们要比较的值只需要使用x => x进行选择即可。这个lamba取值并再次返回。

答案 2 :(得分:1)

请参阅代码中的注释以获取解释。

using System;
using System.Linq;

class Program
{
    static void Main()
    {
        //var inputs = new [] { 40, 8, 16, 6 }; // total = 114
        var inputs = new[] { 62, 14, 2, 6, 28, 41 }; // total = 324

        var total = 0;
        var query = inputs.AsEnumerable();
        while (query.Count() > 1)
        {
            // sort the numbers
            var sorted = query.OrderBy(x => x).ToList();
            // get sum of the first two smallest numbers
            var sumTwoSmallest = sorted.Take(2).Sum();
            // count total
            total += sumTwoSmallest;
            // remove the first two smallest numbers
            query = sorted.Skip(2);
            // add the sum of the two smallest numbers into the numbers
            query = query.Append(sumTwoSmallest);
        }
        Console.WriteLine($"Total = {total}");

        Console.WriteLine("Press any key...");
        Console.ReadKey(true);
    }
}

我对我的代码进行了基准测试,在处理大型数据集时结果很糟糕。我怀疑是因为循环中的排序。需要排序是因为我需要在每次迭代中找到2个最小的数字。所以我认为我需要一种更好的方法来解决这个问题。我使用PriorityQueue(来自visualstudiomagazine.com),因为元素是根据优先级出队的,在这种情况下,数字越小优先级越高。

long total = 0;
while (pq.Count() > 0)
{
    // get two smallest numbers when the priority queue is not empty
    int sum = (pq.Count() > 0 ? pq.Dequeue() : 0) + (pq.Count() > 0 ? pq.Dequeue() : 0);
    total += sum;
    // put the sum of two smallest numbers in the priority queue if the queue is not empty
    if (pq.Count() > 0) pq.Enqueue(sum);
}

以下是发行版本中新(优先级队列)代码和旧代码的一些基准测试结果。结果以毫秒为单位。我没有用旧代码测试100万个数据,因为它太慢了。

+---------+----------+-------------+
|  Data   |   New    |     Old     |
+---------+----------+-------------+
|   10000 |   3.9158 |   5125.9231 |
|   50000 |  16.8375 | 147219.4267 |
| 1000000 | 406.8693 |             |
+---------+----------+-------------+

完整代码:

using System;
using System.Diagnostics;
using System.IO;
using System.Linq;

class Program
{
    static void Main()
    {
        const string fileName = @"numbers.txt";
        using (var writer = new StreamWriter(fileName))
        {
            var random = new Random();
            for (var i = 0; i < 10000; i++)
                writer.WriteLine(random.Next(100));
            writer.Close();
        }

        var sw = new Stopwatch();

        var pq = new PriorityQueue<int>();
        var numbers = File.ReadAllLines(fileName);
        foreach (var number in numbers)
            pq.Enqueue(Convert.ToInt32(number));

        long total = 0;
        sw.Start();
        while (pq.Count() > 0)
        {
            // get two smallest numbers when the priority queue is not empty
            int sum = (pq.Count() > 0 ? pq.Dequeue() : 0) + (pq.Count() > 0 ? pq.Dequeue() : 0);
            total += sum;
            // put the sum of two smallest numbers in the priority queue if the queue is not empty
            if (pq.Count() > 0) pq.Enqueue(sum);
        }
        sw.Stop();
        Console.WriteLine($"Total = {total}");
        Console.WriteLine($"Time = {sw.Elapsed.TotalMilliseconds}");

        total = 0;
        var query = File.ReadAllLines(fileName).Select(x => Convert.ToInt32(x));
        sw.Restart();
        while (query.Count() > 0)
        {
            // sort the numbers
            var sorted = query.OrderBy(x => x).ToList();
            // get sum of the first two smallest numbers
            var sumTwoSmallest = sorted.Take(2).Sum();
            // count total
            total += sumTwoSmallest;
            // remove the first two smallest numbers
            query = sorted.Skip(2);
            // add the sum of the two smallest numbers into the numbers
            if (query.Count() > 0)
                query = query.Append(sumTwoSmallest);
        }
        sw.Stop();
        Console.WriteLine($"Total = {total}");
        Console.WriteLine($"Time = {sw.Elapsed.TotalMilliseconds}");

        Console.WriteLine("Press any key...");
        Console.ReadKey(true);
    }
}

PriorityQueue代码:

using System;
using System.Collections.Generic;

// From http://visualstudiomagazine.com/articles/2012/11/01/priority-queues-with-c.aspx
public class PriorityQueue<T> where T : IComparable<T>
{
    private List<T> data;

    public PriorityQueue()
    {
        this.data = new List<T>();
    }

    public void Enqueue(T item)
    {
        data.Add(item);
        int ci = data.Count - 1; // child index; start at end
        while (ci > 0)
        {
            int pi = (ci - 1) / 2; // parent index
            if (data[ci].CompareTo(data[pi]) >= 0)
                break; // child item is larger than (or equal) parent so we're done
            T tmp = data[ci];
            data[ci] = data[pi];
            data[pi] = tmp;
            ci = pi;
        }
    }

    public T Dequeue()
    {
        // assumes pq is not empty; up to calling code
        int li = data.Count - 1; // last index (before removal)
        T frontItem = data[0];   // fetch the front
        data[0] = data[li];
        data.RemoveAt(li);

        --li; // last index (after removal)
        int pi = 0; // parent index. start at front of pq
        while (true)
        {
            int ci = pi * 2 + 1; // left child index of parent
            if (ci > li)
                break;  // no children so done
            int rc = ci + 1;     // right child
            if (rc <= li && data[rc].CompareTo(data[ci]) < 0) // if there is a rc (ci + 1), and it is smaller than left child, use the rc instead
                ci = rc;
            if (data[pi].CompareTo(data[ci]) <= 0)
                break; // parent is smaller than (or equal to) smallest child so done
            T tmp = data[pi];
            data[pi] = data[ci];
            data[ci] = tmp; // swap parent and child
            pi = ci;
        }
        return frontItem;
    }

    public T Peek()
    {
        T frontItem = data[0];
        return frontItem;
    }

    public int Count()
    {
        return data.Count;
    }

    public override string ToString()
    {
        string s = "";
        for (int i = 0; i < data.Count; ++i)
            s += data[i].ToString() + " ";
        s += "count = " + data.Count;
        return s;
    }

    public bool IsConsistent()
    {
        // is the heap property true for all data?
        if (data.Count == 0)
            return true;
        int li = data.Count - 1; // last index
        for (int pi = 0; pi < data.Count; ++pi)
        { // each parent index
            int lci = 2 * pi + 1; // left child index
            int rci = 2 * pi + 2; // right child index

            if (lci <= li && data[pi].CompareTo(data[lci]) > 0)
                return false; // if lc exists and it's greater than parent then bad.
            if (rci <= li && data[pi].CompareTo(data[rci]) > 0)
                return false; // check the right child too.
        }
        return true; // passed all checks
    }
    // IsConsistent
}
// PriorityQueue

参考:

答案 3 :(得分:1)

我将使用使用LINQ的最简单的单行解决方案版本:

Array.Sort(specs);
int total = specs.Select((n, i) => specs.Take(i + 1).Sum()).Sum() - (specs.Length > 1 ? specs[0] : 0);

答案 4 :(得分:0)

您可以简单地使用Array.Sort()对它进行排序,然后将其总和存入一个以最小值开头的新数组中,并将每个下一个值加到最近的总和中,总和就是最后一个总和的值

public static int time(int vehicles, int[] specs)
{
    int i, total;
    int[] sums = new int[vehicles];
    Array.Sort(spec);
    sums[0] = specs[0];
    for (i = 1; i < vehicles; i++)
        sums[i] = sums[i - 1] + spec[i];
    total = sums[spec - 1];
}