如何根据日期合并两个列表

时间:2019-02-15 12:03:25

标签: c# algorithm

我有两个字符串列表,第一个列表包含对应于每个元素的第二个列表的ID。列表的定义

IdsList ["Id1","Id2"]
ShippingsNoList ["n1,n2..","t1,t2"] 

表示n1,n2->Id1, t1,t2->Id2

IdsList格式-> A-date-B ShippingNumbersList格式-> number1,number2,etc.

我的目的是将两个列表结合起来并以字符串形式返回结果。如果我发现与另一个发运号相等的发运号及其编号的日期也应匹配,那么我应该获得发运号和相关ID。一个发货编号可能已经分配了多个日期相同的编号。 示例:

IdsList=["A-28.03.18-B", 
         "S-17.05.18-G", 
         "L-17.05.18-P",
         "M-28.03.18-T",
         "B-17.05.18-U"]

ShippingNumbersList=["100,200,300", 
                      "100,900", 
                      "200,300,100",
                      "100,900,300",
                      "100,300"]

预期结果:

100-> A-28.03.18-B,M-28.03.18-T
300-> A-28.03.18-B,M-28.03.18-T
100-> S-17.05.18-G,L-17.05.18-P,B-17.05.18-U
300-> L-17.05.18-P, B-17.05.18-U

3 个答案:

答案 0 :(得分:1)

尝试使用LINQ“美容”。

var idsList = new string[]
{
    "A-28.03.18-B",
    "S-17.05.18-G",
    "L-17.05.18-P",
    "M-28.03.18-T",
    "B-17.05.18-U"
};

var shippingNumbersList = new string[]
{
    "100,200,300",
    "100,900",
    "200,300,100",
    "100,900,300",
    "100,300"
};

var data = idsList
.Zip(shippingNumbersList, (x, y) =>
{
    //parse the entry of the idsList ('x') in a dateTime
    var date = DateTime.Parse(x.Split("-")[1]); //<-- may need to use DateTime.ParseExact(x.Split('-')[1], "dd.MM.yy", CultureInfo.InvariantCulture) - depending on the culture you are using, this will now work on any machine

    //parse the entry of the shippingNumbersList ('y') in a IEnumerable<int>
    var numbers = y.Split(",").Select(int.Parse);

    //make a IEnumerable of the two different data, consisting of (Id, Date, ShippingNumber) <- a single ShippingNumber, thats why we call numbers.Select
    return numbers.Select(number => (Id: x, Date: date, ShippingNumber: number));
}) //<-- use ZIP to combine the two lists together
.SelectMany(x => x) //<-- use SELECTMANY to get a flat list of each "id" with the x number of "shippingNumberList"
.GroupBy(x => (Date: x.Date, ShippingNumber: x.ShippingNumber)) //<-- use GROUPBY for the Date and ShippingNumber
.Where(x => x.Count() > 1) //<-- use WHERE to filter those who only have 1 entry in a group consisting of Date+ShippingNumber
.Select(x => x.Key.ShippingNumber + "-> " + string.Join(",", x.Select(y => y.Id))) //<-- use SELECT to resolve the group to a string, there the Key is the combined Date + ShippingNumber and the Value is the flatList of that group
.ToList(); //<-- use TOLIST to make a List out of the IEnumerable

已经修复了一些问题,使其可以在dotnetfiddle上运行,但是您可以在这里: https://dotnetfiddle.net/bKpUDz

答案 1 :(得分:0)

这是另一种经过测试的解决方案:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Data;
using System.Text.RegularExpressions;

namespace ConsoleApplication100
{

    class Program
    {
        static void Main(string[] args)
        {
            List<string> IdsList = new List<string>() {
                                 "A-28.03.18-B",
                                 "S-17.05.18-G", 
                                 "L-17.05.18-P",
                                 "M-28.03.18-T",
                                 "B-17.05.18-U"
                              };
            List<string> ShippingNumbersList = new List<string>() {
                                              "100,200,300", 
                                              "100,900", 
                                              "200,300,100",
                                              "100,900,300",
                                              "100,300"
                                          };
            var results = Shipping.MergeList(IdsList, ShippingNumbersList);
        }

    }
    public class Shipping
    {

        public static object MergeList(List<string> ids, List<string> numbers)
        {
            string pattern = @"\w-(?'day'[^\.]+)\.(?'month'[^\.]+)\.(?'year'[^-]+)";

            List<KeyValuePair<DateTime, string>> idDates = new List<KeyValuePair<DateTime,string>>();
            foreach(string id in ids)
            {
                Match match = Regex.Match(id,pattern);
                idDates.Add(new KeyValuePair<DateTime, string>( new DateTime(2000 + int.Parse(match.Groups["year"].Value), int.Parse(match.Groups["month"].Value), int.Parse(match.Groups["day"].Value)), id));
            }

            var groups = idDates.SelectMany((x, i) => numbers[i].Split(new char[] {','}).Select(y => new { idDate = x, number = y })).ToList();

            var groupDates = groups.GroupBy(x => new { date = x.idDate.Key, number = x.number }).ToList();

            var results = groupDates.Select(x => new { number = x.Key.number, ids = x.Select(y => y.idDate.Value).ToList() }).ToList();

            return results;
        }
    }

}

答案 2 :(得分:0)

数据:

var IdsList =new string[] {"A-28.03.18-B",
    "S-17.05.18-G",
    "L-17.05.18-P",
    "M-28.03.18-T",
    "B-17.05.18-U" };

var ShippingNumbersList =new string[] {"100,200,300",
                        "100,900",
                        "200,300,100",
                        "100,900,300",
                        "100,300" };

制作结果:

//normalizing data and make a list of joined columns
var normalizedlist = IdsList
.Select((Ids, index) => new { Ids = Ids, ShippingNumbers = ShippingNumbersList[index].Split(',') })
    .ToList();
//for each distinct ShippingNumber find and write respective Id
foreach (var ShippingNumber in normalizedlist.SelectMany(x=>x.ShippingNumbers).Distinct())
{
    //fitering and then grouping by date 
    var filtered = normalizedlist.Where(y => y.ShippingNumbers.Contains(ShippingNumber))
        .GroupBy(y => y.Ids.Split('-')[1])
        .Where(y => y.Count() > 1)
        .Select(y => y.Select(z=>z.Ids));
    foreach (var date in filtered)
    {
    Console.WriteLine($"{ShippingNumber}>>{string.Join(",",date.ToArray())}");
    }
}

输出:

100>>A-28.03.18-B,M-28.03.18-T
100>>S-17.05.18-G,L-17.05.18-P,B-17.05.18-U
300>>A-28.03.18-B,M-28.03.18-T
300>>L-17.05.18-P,B-17.05.18-U