简体   繁体   English

我怎样才能使这个 linq 查询更清晰、更可重用?

[英]How can i make this linq query cleaner and more reusable?

I have a linq query that returns the count of several ring sizes.我有一个 linq 查询,它返回几个环大小的计数。 However even though it is reusablable to an extent i want to see if i can improve it.然而,即使它在某种程度上可以重复使用,我也想看看我是否可以改进它。

    private async Task<RingSizeLettersDto> CountOfLettersByRingFingerAsync(Func<RingSize, string> selector)
    {
        var ringSizes = await _ringSizeRepository.Get();

        RingSizeLettersDto ringSizeLetters = new RingSizeLettersDto();

        ringSizeLetters.G = ringSizes.Where(x => selector(x) == "G").Count();
        ringSizeLetters.H = ringSizes.Where(x => selector(x) == "H").Count();
        ringSizeLetters.I = ringSizes.Where(x => selector(x) == "I").Count();
        ringSizeLetters.J = ringSizes.Where(x => selector(x) == "J").Count();
        ringSizeLetters.K = ringSizes.Where(x => selector(x) == "K").Count();
        ringSizeLetters.L = ringSizes.Where(x => selector(x) == "L").Count();
        ringSizeLetters.M = ringSizes.Where(x => selector(x) == "M").Count();
        ringSizeLetters.N = ringSizes.Where(x => selector(x) == "N").Count();
        ringSizeLetters.O = ringSizes.Where(x => selector(x) == "O").Count();
        ringSizeLetters.P = ringSizes.Where(x => selector(x) == "P").Count();
        ringSizeLetters.Q = ringSizes.Where(x => selector(x) == "Q").Count();
        ringSizeLetters.R = ringSizes.Where(x => selector(x) == "R").Count();
        ringSizeLetters.S = ringSizes.Where(x => selector(x) == "S").Count();
        ringSizeLetters.T = ringSizes.Where(x => selector(x) == "T").Count();
        ringSizeLetters.U = ringSizes.Where(x => selector(x) == "U").Count();
        ringSizeLetters.V = ringSizes.Where(x => selector(x) == "V").Count();
        ringSizeLetters.W = ringSizes.Where(x => selector(x) == "W").Count();
        ringSizeLetters.X = ringSizes.Where(x => selector(x) == "X").Count();
        ringSizeLetters.Y = ringSizes.Where(x => selector(x) == "Y").Count();
        ringSizeLetters.Z = ringSizes.Where(x => selector(x) == "Z").Count();
        ringSizeLetters.Z1 = ringSizes.Where(x => selector(x) == "Z1").Count();
        ringSizeLetters.Z2 = ringSizes.Where(x => selector(x) == "Z2").Count();
        ringSizeLetters.Z3 = ringSizes.Where(x => selector(x) == "Z3").Count();
        ringSizeLetters.Z4 = ringSizes.Where(x => selector(x) == "Z4").Count();
        ringSizeLetters.Z5 = ringSizes.Where(x => selector(x) == "Z5").Count();
        ringSizeLetters.Z6 = ringSizes.Where(x => selector(x) == "Z6").Count();
        ringSizeLetters.NA = ringSizes.Where(x => selector(x) == "N/A").Count();

        return ringSizeLetters;

    }

I have to improvements in mind:我必须牢记改进:

  • You can use Count(x => selector(x) == "G") , which will reduce 1 method invocation per line.您可以使用Count(x => selector(x) == "G") ,这将减少每行 1 个方法调用。

  • You can create a Dictionary<string, int> (probably char as key can be more accurate) which represents the count by character, then elsewhere in you application you can access it using the character you want to search for as a key:您可以创建一个Dictionary<string, int> (可能char as key 可能更准确),它表示按字符计数,然后在应用程序的其他地方,您可以使用要搜索的字符作为键来访问它:

var ringSizes = new[] { 1, 2, 2 };
var ringSizeLetters = ringSizes.GroupBy(x => Selector(x))
     .ToDictionary(x => x.Key, v => v.Count());

var ocurrences = ringSizeLetters["A"];


Depending on whether your specific use case allows for this, a cleaner solution would be to use a Dictionary.根据您的特定用例是否允许这样做,更简洁的解决方案是使用字典。 Judging from your code the best type would be IDictionary<string, int> .从你的代码来看,最好的类型是IDictionary<string, int> In this, the string key is the identifier (such as 'Z1') and the integer value is the result of .Count() .在这里,字符串键是标识符(例如 'Z1'),整数值是.Count()的结果。

I've coughed up a possible code sample below;我在下面列出了一个可能的代码示例;

public static IDictionary<string, int> GetRingSizeLettersAsDict(
    IEnumerable<string> sizeLetters,
    IEnumerable<object> ringSizes)
{
    IDictionary<string, int> ringSizeLetters = new();

    sizeLetters.Select(
        sl => ringSizeLetters.Add(
            sl,
            ringSizes.Where(rs => selector(rs).Equals(sl)).Count())
    );

    return ringSizeLetters;
}

This is just one of many solutions, but it should do the same as your code example, provided it fits your use case.这只是众多解决方案之一,但它应该与您的代码示例相同,前提是它适合您的用例。

This is type of speudo-code but something like this should do the trick..这是一种伪代码,但这样的事情应该可以解决问题..

It is done via System.Reflection它是通过 System.Reflection 完成的

                PropertyInfo[] properties = ringSizeLetters.GetProperties();
                foreach (PropertyInfo property in properties)
                {
                   var propertyName = property.Name;
                   var ringsizeValue = ringSizes.SingleOrDefault(x=> x.PROPERTYNAME == propertyName)
    
                   // if it finds ringsize Value 
                  if(ringsizeValue != null)
                  {
                     property.SetValue(ringSizeLetters, ringsizeValue.Count());
                  }
    
                }

You can keep all your properties if you really want them:如果您真的想要它们,您可以保留所有属性:

class RingSizeDto{

  public int G { get; set;}
  public int H { get; set;}

... and avoid reflection by backing them with eg a dictionary instead: ...并通过使用例如字典来支持它们来避免反射:

class RingSizeDto{

  private Dictionary<string, int> _ringSizes = new();

  public int G { get => _ringSizes[nameof(G)]; set _ringSizes[nameof(G)] = value; }
  public int H { get => _ringSizes[nameof(H)]; set _ringSizes[nameof(H)] = value; }
  ...

This means the sizes can be set all in one go by providing the dictionary:这意味着可以通过提供字典一次性设置大小:

  public RingSizeDto(Dictionary <string, int> sizes){
    _ringSizes = sizes;
  }

And the dictionary can be generated by query eg字典可以通过查询生成,例如

var sizes = someSizeList.GroupBy(s => s.SizeLetter).ToDictionary(g => g.Key, g => g.Count());

new RingSizeDto(sizes);

Note;笔记; if your list doesn't have every possible size, you'll want to avoid a crash on the dictionary access by using TryGetValue instead如果您的列表没有所有可能的大小,您将希望通过使用 TryGetValue 来避免字典访问崩溃

public int G { get => _ringSizes.TryGetValue(nameof(G), out var x) ? x : 0; set _ringSizes[nameof(G)] = value; }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM