【问题标题】:Reorganize values in 3 arrays based off a unique combination of values in 2 of the arrays in C#根据 C# 中 2 个数组中的值的唯一组合重新组织 3 个数组中的值
【发布时间】:2015-03-24 21:19:57
【问题描述】:

我有 3 个数据类型如下的数组:

string[] arrID = {"111", "222", "333", "444", "555", "666", "777"};

DateTime[] arrDates = new DateTime[]
{
    new DateTime(2015, 03, 20),
    new DateTime(2015, 03, 20),
    new DateTime(2015, 03, 20),
    new DateTime(2015, 03, 21),
    new DateTime(2015, 03, 21),
    new DateTime(2015, 03, 20),
    new DateTime(2015, 03, 20)
};

string[] arrTime = {"8:20", "8:40", "8:20", "9:10", "8:20", "9:10", "8:20"};

我已将示例元素添加到 3 个数组中,以模拟我们将在这些数组中拥有的数据类型。

每个元素中的每个索引号都包含与一条记录相关的值。

示例:每个索引为 3 的数组中的值包含构成一条记录的值。

我需要根据以下条件将这 3 个数组中的值放入以下 ​​3 个数组中:arrNEWIDarrNEWDatearrNEWTime

  • 对于每个唯一的日期和时间组合,需要向每个数组添加一个单独的元素。
  • 如果唯一的日期和时间组合有多个 ID,则这些 ID 需要用逗号分隔。

3 个新数组中的预期输出

--------------------------------------------------
| index | arrNEWDate | arrNEWTime | arrNEWID     |
-------------------------------------------------- 
|  0    | 03/20/2015 | 8:20       | 111,333,777  |
|  1    | 03/20/2015 | 8:40       | 222          |
|  2    | 03/20/2015 | 9:10       | 666          |
|  3    | 03/21/2015 | 8:20       | 555          |
|  4    | 03/21/2015 | 9:10       | 444          |

注意事项:

  • 3个NEW数组的数据类型需要是string
  • 输入和输出需要保持为数组。可以创建列表进行处理

这是我已经使用过的代码:

string[] arrID = { "111", "222", "333", "444", "555", "666", "777" };

DateTime[] arrDates = new DateTime[]
{
    new DateTime(2015, 03, 20),
    new DateTime(2015, 03, 20),
    new DateTime(2015, 03, 20),
    new DateTime(2015, 03, 21),
    new DateTime(2015, 03, 21),
    new DateTime(2015, 03, 20),
    new DateTime(2015, 03, 20)
};

string[] arrTime = { "8:20", "8:40", "8:20", "9:10", "8:20", "9:10", "8:20" };

string str_arrNEWID = "";
string str_arrNEWDate = "";
string str_arrNEWTime = "";
string[] arrNEWID = "".Split('~');
string[] arrNEWDate = "".Split('~');
string[] arrNEWTime = "".Split('~');

for (int i = 0; i <= arrID.GetUpperBound(0); i++)
{
    int intExists = 0;

    for (int j = 0; j <= arrNEWDate.GetUpperBound(0); j++)
    {
        //check if date matches for the current index being checked
        if (arrNEWDate[j].ToString() == arrDates[i].Date.ToString("MM/dd/yyyy"))
        {
            //check if time matches for the same index
            if (arrNEWTime[j].ToString() == arrTime[i].ToString())
            {
                //existing record
                intExists = 1;
                arrNEWID[j] = arrNEWID[j] + "," + arrID[i];
                str_arrNEWID = string.Join("~", arrNEWID);
            }
        }

    }

    if (intExists == 0)
    {
        //new record
        str_arrNEWDate = str_arrNEWDate + "~" + arrDates[i].Date.ToString("MM/dd/yyyy") ;
        arrNEWDate = str_arrNEWDate.Split('~');

        str_arrNEWTime = str_arrNEWTime + "~" + arrTime[i].ToString() ;
        arrNEWTime = str_arrNEWTime.Split('~');

        str_arrNEWID = str_arrNEWID + "~" + arrID[i];
        arrNEWID = str_arrNEWID.Split('~');
    }
}

主要的挑战是需要用来编译这段代码的编译器不支持 lambda 运算符(=>)

我需要知道:

  1. 如果有办法让我不必每次都使用临时字符串变量和拆分函数来刷新数组

  2. 如果有办法摆脱多重循环

【问题讨论】:

  • 你试过什么?那段代码做了什么?这与您期望或希望它做的有什么不同?请参阅stackoverflow.com/help/how-to-ask,获取有关如何以清晰、可回答的方式提出问题的建议。
  • 我已经添加了这些细节。谢谢你的时间:)
  • 问题已更新。请删除或解释否决票

标签: c# arrays algorithm


【解决方案1】:

数组让一切变得更加困难。

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using System.Linq;

namespace UnitTestProject1
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            string[] arrID = { "111", "222", "333", "444", "555", "666", "777" };

            DateTime[] arrDates = new DateTime[]
            {
                new DateTime(2015, 03, 20),
                new DateTime(2015, 03, 20),
                new DateTime(2015, 03, 20),
                new DateTime(2015, 03, 21),
                new DateTime(2015, 03, 21),
                new DateTime(2015, 03, 20),
                new DateTime(2015, 03, 20)
            };

            string[] arrTime = { "8:20", "8:40", "8:20", "9:10", "8:20", "9:10", "8:20" };

            int i = -1;
            int index = 0;
            List<ewansObject> l2 = arrID.Select(o => new ewansObject() { date = arrDates[++i].ToString(), time = arrTime[i], id = arrID[i] }).GroupBy(k => k.date + k.time).Select(o => new ewansObject() { index = index++.ToString(), date = o.First().date, time = o.First().time, id = String.Join(",", o.Select(x => x.id)) }).ToList(); ;

            string[] arrNEWID = l2.Select(x => x.id).ToArray();
            string[] arrNEWDate = l2.Select(x => x.date).ToArray();
            string[] arrNEWTime = l2.Select(x => x.time).ToArray();

            Console.WriteLine(String.Join("|", arrNEWID));
            Console.WriteLine(String.Join("|", arrNEWDate));
            Console.WriteLine(String.Join("|", arrNEWTime));
        }

        public class ewansObject
        {
            public string index;
            public string date;
            public string time;
            public string id;
        }
    }
}

也许我应该把我的名字改成 homework4points

【讨论】:

  • 谢谢。但是,不使用 lambda 运算符是否可以做到这一点?
【解决方案2】:

.NET 中的 LINQ 功能可以很容易地处理您正在寻找的那种处理方式。特别是,LINQ 包括非常方便的group...byorderby,它们直接适用于您的场景。不幸的是,普通的 LINQ 语法也严重依赖于 lambda 语法,你说你不能使用。

但是,请注意 lambda 语法只是一种“语法糖”,即一种向编译器表达某些内容的方式,您可以用更冗长的方式自己编写。特别是,这里使用的 lambda 语法会生成匿名方法,您当然可以将其写为命名方法。

匿名方法还允许“捕获”变量,但在您的场景中,我们可以通过做两件事来避免需要捕获任何变量:

  1. 将数据放在类字段中,命名方法可以访问它们
  2. 使用 Enumerable.Select() 重载将索引传递给选择器方法,以便命名方法可以将源项与其他两个数组中相互关联的元素相关联

同样,虽然匿名类型在这里很方便,但有效使用这些依赖于匿名方法并为这些匿名方法推断方法参数的类型。取而代之的是,Tuple 类也同样适用。

将所有这些放在一起,我们会得到如下所示的东西:

class Program
{
    static readonly string[] arrID = { "111", "222", "333", "444", "555", "666", "777" };

    static readonly DateTime[] arrDates = new DateTime[]
    {
        new DateTime(2015, 03, 20),
        new DateTime(2015, 03, 20),
        new DateTime(2015, 03, 20),
        new DateTime(2015, 03, 21),
        new DateTime(2015, 03, 21),
        new DateTime(2015, 03, 20),
        new DateTime(2015, 03, 20)
    };

    static readonly string[] arrTime = { "8:20", "8:40", "8:20", "9:10", "8:20", "9:10", "8:20" };

    static void Main(string[] args)
    {
        // Generate intermediate query with grouped, ordered data
        Tuple<DateTime, string>[] q = arrID.Select(CreateRecord)
            .GroupBy(GetKey)
            .OrderBy(GetGroupKey)
            .Select(FlattenGroup)
            .ToArray();

        // Final output arrays here
        string[] str_arrNEWDate = new string[q.Length],
            str_arrNEWTime = new string[q.Length],
            str_arrNEWID = new string[q.Length];

        for (int i = 0; i < q.Length; i++)
        {
            str_arrNEWDate[i] = q[i].Item1.ToString("MM/dd/yyyy");
            str_arrNEWTime[i] = q[i].Item1.ToString("HH:mm");
            str_arrNEWID[i] = q[i].Item2;

            // Diagnostic for demonstration purposes
            Console.WriteLine("{0}: {1}", q[i].Item1, q[i].Item2);
        }
    }

    private static Tuple<DateTime, string> CreateRecord(string id, int index)
    {
        return Tuple.Create(arrDates[index] + TimeSpan.Parse(arrTime[index]), id);
    }

    private static DateTime GetKey(Tuple<DateTime, string> record)
    {
        return record.Item1;
    }

    private static DateTime GetGroupKey(IGrouping<DateTime, Tuple<DateTime, string>> group)
    {
        return group.Key;
    }

    private static Tuple<DateTime, string> FlattenGroup(IGrouping<DateTime, Tuple<DateTime, string>> group)
    {
        return Tuple.Create(group.Key, string.Join(",", group.Select(GetId)));
    }

    private static string GetId(Tuple<DateTime, string> record)
    {
        return record.Item2;
    }
}

如您所见,在您通常会编写 lambda 表达式的任何地方,在上面我们只是有一个常规的 static 方法来完成这项工作。请注意,如果您处理的是非static 类和访问实例成员所需的方法,则可以简单地将这些方法设为非static

委托类型推断负责构建需要传递给 LINQ 方法的委托实例。


注意:虽然您没有在问题中明确说明,但规范的性质强烈暗示这是家庭作业。因此,您应该确保花时间真正理解上面的代码示例。否则你什么都学不到,浪费你在课堂上的时间。请随时在此处就我的答案提出问题,当然,您应该很乐意让您的老师帮助您理解原始作业和此答案。

【讨论】:

    猜你喜欢
    • 2014-06-19
    • 1970-01-01
    • 2014-07-24
    • 2022-01-01
    • 1970-01-01
    • 2019-08-16
    • 2023-03-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多