与LINQ查询取代开关回路 [英] Replace for-switch loop with a Linq query

查看:111
本文介绍了与LINQ查询取代开关回路的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个包裹,我没有控制权的消息格式Message对象。格式是键/值对的简单列表。我想从一个给定的消息中提取用户列表。例如,给定下面的消息...

I have a Message object which wraps a message format I do not have control over. The format is a simple list of Key/Value pairs. I want to extract a list of Users from a given Message. For example given the following message...

1. 200->....
2. 300->....
3. ....
4. 405->.... 
5. 001->first_user_name
6. 002->first_user_phone
7. 003->first_user_fax
8. 001->second_user_name
9. 001->third_user_name
10. 002->third_user_phone
11. 003->third_user_fax
12. 004->third_user_address
13. .....
14. 001->last_user_name
15. 003->last_user_fax  

我想提取四个用户使用所提供的属性进行设置。初始密钥200/300 .... 405代表我不需要字段和可以跳到获取到的用户数据。

I want to extract four Users with the provided properties set. The initial keys 200/300....405 represent fields I don't need and can skip to get to the User data.

每个用户的数据是在连续场而场的数目取决于多少信息知道关于用户。下面的方法做什么我要找的。它使用可能的密钥类型和方法的枚举找到的第一个字段的用户数据的索引。

Each users data is in consecutive fields but the number of fields varies depending on how much information is known about a user. The following method does what I'm looking for. It uses an enumeration of possible key types and a method to find the index of the first field with user data.

private List<User> ParseUsers( Message message )
{
    List<User> users = new List<User>( );
    User user = null; String val = String.Empty;

    for( Int32 i = message.IndexOfFirst( Keys.Name ); i < message.Count; i++ ) 
    {
        val = message[ i ].Val;

        switch( message[ i ].Key )
        {
            case Keys.Name:
                user = new User( val );
                users.Add( user ); 
                break;
            case Keys.Phone:
                user.Phone = val;
                break;
            case Keys.Fax:
                user.Fax = val;
                break;
            case Keys.Address:
                user.Address = val;
                break;
            default:
                break;
        }
    }

    return users;
}



我想知道如果有可能取代与LINQ查询方法。我无法告诉LINQ到选择一个新的用户,并直到找到下一个用户入口开始填充它的领域与所有匹配的数据。

I'm wondering if its possible to replace the method with a Linq query. I'm having trouble telling Linq to select a new user and populate its fields with all matching data until you find the start of the next user entry.

注:相对关键数字是真实的消息格式随机的(未1,2,3,4)

Note: Relative key numbers are random (not 1,2,3,4) in the real message format.

推荐答案

我看不到好处改变你的代码,LINQ查询,但它绝对有可能:

I don't see the benefit in changing your code to a LINQ query, but it's definitely possible:

private List<User> ParseUsers(Message message)
{
    return Enumerable
        .Range(0, message.Count)
        .Select(i => message[i])
        .SkipWhile(x => x.Key != Keys.Name)
        .GroupAdjacent((g, x) => x.Key != Keys.Name)
        .Select(g => g.ToDictionary(x => x.Key, x => x.Val))
        .Select(d => new User(d[Keys.Name])
        {
            Phone   = d.ContainsKey(Keys.Phone)   ? d[Keys.Phone]   : null,
            Fax     = d.ContainsKey(Keys.Fax)     ? d[Keys.Fax]     : null,
            Address = d.ContainsKey(Keys.Address) ? d[Keys.Address] : null,
        })
        .ToList();
}



使用

using

static IEnumerable<IEnumerable<T>> GroupAdjacent<T>(
    this IEnumerable<T> source, Func<IEnumerable<T>, T, bool> adjacent)
{
    var g = new List<T>();
    foreach (var x in source)
    {
        if (g.Count != 0 && !adjacent(g, x))
        {
            yield return g;
            g = new List<T>();
        }
        g.Add(x);
    }
    yield return g;
}

这篇关于与LINQ查询取代开关回路的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆