列表排序和模式匹配

列表排序和模式匹配

本文介绍了列表排序和模式匹配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将电报列表排序为从属列表.

I'm trying to sort a list of telegramms to a List of Slaves.

如果PrimeAddress和SecondaryAddress匹配,则电报属于从站.

If the PrimeAddress and the SecondaryAddress match, the telegrams belongs to the Slave.

设备存储在数据表中.

The devices are stored in a Datatable.

我想检查设备是否已经包含电报.

I want to check if the deivce already contains the telegramm.

我的第一次尝试是这样的:

My first attempt looks something like this:

public static DataTable mdlform_NewMBUStele(int LoggerID, List<MbusTelegram> mList, DataTable _deviceDataTable)
    {
        //TODO Das ist total dirty und gar nicht clean hier...
        foreach (DataRow dRow in _deviceDataTable.Rows)
        {
            if (dRow.ItemArray[3] is Slave)
            {
                foreach (MbusTelegram mb in mList)
                {
                    int primeID = (int)dRow.ItemArray[1];
                    if (primeID == LoggerID)
                    {
                        Slave slv = (Slave)dRow.ItemArray[3];
                        foreach (MbusTelegram mbus in mList)
                        {
                            if (slv.PrimeAddress == mbus.Header.PrimeAddress && slv.SecondaryAdd == mbus.FixedDataHeader.SecondaryAddress)
                            {
                                if (slv.ListOfTelegramms == null)
                                {
                                    slv.ListOfTelegramms = new List<MbusTelegram>();
                                }
                                if (!slv.ListOfTelegramms.Contains(mbus))
                                {
                                    slv.ListOfTelegramms.Add(mbus);
                                    //TODO Check if the slave already contains the telegramm, if so don't add it..
                                }
                            }
                        }
                    }
                }
            }
        }
        return _deviceDataTable;
    }

数据表的结构:

private void IniDataTable()
    {
        _deviceDataTable = new DataTable("Table");
        _deviceDataTable.Columns.Add("ID", typeof(int));
        _deviceDataTable.Columns.Add("IDParent", typeof(int));
        _deviceDataTable.Columns.Add("Name", typeof(string));
        _deviceDataTable.Columns.Add("Object", typeof(object));
        _deviceDataTable.Rows.Add(new object[] { 0, DBNull.Value, "Addressen", null });
        //GenerateDummyDataTable();
        IniDeviceTreeView();
    }

此代码无法很好地工作,并且无法检查设备是否已包含电报.还有更好的主意吗?

This code doesn't work very well and it doesn't check if the device already contains the telegramm. Any better ideas?

推荐答案

您可以做一些事情来优化代码.首先,将所有不变的东西带出内循环.例如.您使用ItemArray的每种类型.对于内部循环的每次迭代,它们都不会改变,但是第二次,随着外部循环的每次迭代,您似乎都在同一集合上进行了两次迭代,而从未使用外部循环(mb)的变量,因此您可以完全消除该循环.我已经在下面的代码中完成了这两项工作.我也将最里面的循环转换为LINQ,但这主要是因为我发现它更易于阅读.我不确定Distinct是否可以解决TODO.我不确定我是否完全了解TODO.可能但不一定解决,您需要验证

There's a few things you can do to optimize your code. Firstly take all the things that doesn't change out of the inner loop. E.g. every type you use ItemArray. They are not changing for each iteration of the inner loop but with each iteration of the outer loop secondly you seem to be iterating twice over the same collection never using the variable of the outer loop (mb) so you can eleminate that loop entirely. I've done both in the code below. I've also converted the inner most loop to LINQ but that's mostly because I find it easier to read. I'm not sure the Distinct solves the TODO. I'm not sure I get the TODO at all. It might and it might not solve it you'll need to verify that

public static DataTable mdlform_NewMBUStele(int LoggerID, List<MbusTelegram> mList, DataTable _deviceDataTable){
            //TODO Das ist total dirty und gar nicht clean hier...
            foreach (DataRow dRow in _deviceDataTable.Rows.Cast<DataRow>().Where(d=>d.ItemArray[3] is Slave)){
                    var primeID = (int) dRow.ItemArray[1];
                    var slv = (Slave) dRow.ItemArray[3];
                    if (slv.ListOfTelegramms == null){
                        slv.ListOfTelegramms = new List<MbusTelegram>();
                    }
                    var list = slv.ListOfTelegramms;
                    if (primeID == LoggerID){
                        var items = from m in mList
                                    where
                                        slv.PrimeAddress == m.Header.PrimeAddress &&
                                        slv.SecondaryAdd == m.FixedDataHeader.SecondaryAddress && !list.Contains(m, MbusTelegramEqualityComparer.Default)
                                    select m;
                        list.AddRange(items.Distinct(MbusTelegramEqualityComparer.Default));
                        }
                    }
            return _deviceDataTable;
        }

如果您还希望对其进行LINQify验证,则可以执行以下操作(这可能会导致效果更差):

if you also want to LINQify it for readability you could do as below (this might perform slightly worse):

public static DataTable mdlform_NewMBUStele2(int LoggerID, List<MbusTelegram> mList, DataTable _deviceDataTable){
            var pairs = from dRow in _deviceDataTable.Rows.Cast<DataRow>()
                        where dRow.ItemArray[3] is Slave
                        let primeID = (int) dRow.ItemArray[1]
                        let slv = (Slave) dRow.ItemArray[3]
                        let list = slv.ListOfTelegramms
                        where primeID == LoggerID
                        select
                            new{
                                   list,
                                   items = (from m in mList
                                            where
                                                slv.PrimeAddress == m.Header.PrimeAddress &&
                                                slv.SecondaryAdd == m.FixedDataHeader.SecondaryAddress &&
                                                !list.Contains(m, MbusTelegramEqualityComparer.Default)
                                            select m).Distinct(MbusTelegramEqualityComparer.Default)
                               };
            foreach (var pair in pairs){
                pair.list.AddRange(pair.items);
            }
            return _deviceDataTable;
        }

后一个示例要求将ListOfTelegrams初始化为一个空列表,而不是null

the latter exampl requires that ListOfTelegrams is initialized to an empty list instead of null

编辑要进行价值比较,请使用IEqualityComparer.以下仅将时间戳用于平等.该代码将根据用法进行更新.如果ListOfTelegrams可以包含重复项,则您也需要在调用中将其处理为distinct,否则,可以将对Distinct的调用省去.

EDITto have value comparison use a IEqualityComparer. The below uses the timestamps only for equality. The code is updated with the usage. If the ListOfTelegrams can contain duplicates you'll need to handle this in the call to distinct as well otherwise you can leave the call to Distinct out.

public class MbusTelegramEqualityComparer : IEqualityComparer<MbusTelegram>{
        public static readonly MbusTelegramEqualityComparer Default = new MbusTelegramEqualityComparer();
        public bool Equals(MbusTelegram x, MbusTelegram y){
            return x.TimeStamp == y.TimeStamp;
        }

        public int GetHashCode(MbusTelegram obj){
            return obj.TimeStamp.GetHashCode();
        }
    }

这篇关于列表排序和模式匹配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-13 07:24