【问题标题】:C# Linq questionC# Linq 问题
【发布时间】:2011-04-28 23:37:21
【问题描述】:

我有一个文本文件,我在其中存储地址簿的条目。 布局是这样的:

姓名:
联系方式:
产品:
数量:

我已经编写了一些 linq 代码来获取名称和接下来的四行,用于按名称搜索功能。 我也希望能够按联系人搜索。 挑战是匹配联系信息,抓住接下来的 3 行,并在比赛前抓住行。 这样,如果使用按联系人搜索,则会返回完整的信息列表。

  private void buttonSearch_Click(object sender, EventArgs e)
    {
            string[] lines = File.ReadAllLines("C:/AddressBook/Customers.txt");
            string name = textBoxSearchName.Text;
            string contact = textBoxContact.Text;

            if (name == "" && contact == "")
            {
                return;
            }

            var byName = from line in lines
                         where line.Contains(name)
                         select lines.SkipWhile(f => f != line).Take(4);

            //var byContact = from line in lines
            //                where line.Contains(name)
            //                select lines.SkipWhile(f => f != name).Take(4);


            if (name != "")
            {
                foreach (var item in byName)
                    foreach (var line in item) { listBox2.Items.Add(line); }

                listBox2.Items.Add("");
            }

            //if (contact != "")
            //{
            //    foreach (var item in byContact)
            //        foreach (var line in item) { listBox2.Items.Add(line); }

                //listBox2.Items.Add("");
            }
    }

【问题讨论】:

  • if (name != "") 没有必要,因为您已经检查了 name 是否为空并返回,foreach 将遍历所有找到的项目,因此如果没有,它将不会运行,所以也不是问题。

标签: c# linq


【解决方案1】:

首先,如果可以,我建议您更改数据存储方式。

其次,我建议将文件读入一个对象,如下所示:

public class Contact
{

    public string Name {get; set;}
    public string Contact {get; set;}
    public string Product {get; set;}
    public int Quantity {get; set;}
}
...
public IEnumerable<Contact> GetContacts()
{
    //make this read line by line if it is big!
    string[] lines = File.ReadAllLines("C:/AddressBook/Customers.txt");
    for (int i=0;i<lines.length;i += 4)
    {
        //add error handling/validation!
        yield return new Contact()
        {
              Name = lines[i],
              Contact = lines[i+1],
              Product = lines[i+2],
              Quantity = int.Parse(lines[i+3]
         };
    }
}
private void buttonSearch_Click(object sender, EventArgs e)
{
    ...
    var results = from c in GetContacts()
                 where c.Name == name ||
                       c.Contact == contact
                 select c;
    ...
}

【讨论】:

  • 这非常好而且相当简单,我可能不得不接受。不过我很固执,所以我希望 Linq 在我了解更多信息时屈服于我的意愿 :-)
  • 这是一个在这个和一个正则表达式之间的硬币翻转。我不想做一个正则表达式,所以它是你的。 (虽然我仍然会继续修补 linq)
【解决方案2】:

看看这是否可行

 var contactLinesList = lines.Where(l => l.Contains(name))
                           .Select((l, i) => lines.Skip(i - 1).Take(4)).ToList();


 contactLinesList.ForEach(cl => listBox2.Items.Add(cl));

【讨论】:

    【解决方案3】:

    这不是世界上最小的代码,但它展示了如何做几件事。虽然我不推荐使用它,因为它理解起来相当复杂。这算是业余爱好者,只是学习代码!!!我建议您以众所周知的结构加载文件,然后在上面执行 Linq...无论如何...这是一个 C# 控制台应用程序 使用 Linq 语法 和一个 扩展方法 来完成您建议的操作:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    namespace stackoverflow.com_questions_5826306_c_linq_question
    {
        public class Program
        {
            public static void Main()
            {
                string fileData = @"
    Name: Name-1
    Contact: Xpto
    Product: Abc
    Quantity: 12
    
    Name: Name-2
    Product: Xyz
    Contact: Acme
    Quantity: 16
    
    Name: Name-3
    Product: aammndh
    Contact: YKAHHYTE
    Quantity: 2
    ";
                string[] lines = fileData.Replace("\r\n", "\n").Split('\n');
                var result = Find(lines, "contact", "acme");
                foreach (var item in result)
                    Console.WriteLine(item);
                Console.WriteLine("");
                Console.WriteLine("Press any key");
                Console.ReadKey();
            }
    
            private static string[] Find(string[] lines, string searchField, string searchValue)
            {
                var result = from h4 in
                                 from g4 in
                                     from i in (0).To(lines.Length)
                                     select ((from l in lines select l).Skip(i).Take(4))
                                 where !g4.Contains("")
                                 select g4
                             where h4.Any(
                                 x => x.Split(new char[] { ':' }, 2)[0].Equals(searchField, StringComparison.OrdinalIgnoreCase)
                                     && x.Split(new char[] { ':' }, 2)[1].Trim().Equals(searchValue, StringComparison.OrdinalIgnoreCase))
                             select h4;
                var list = result.FirstOrDefault();
                return list.ToArray();
            }
        }
        public static class NumberExtensions
        {
            public static IEnumerable<int> To(this int start, int end)
            {
                for (int it = start; it < end; it++)
                    yield return it;
            }
        }
    }
    

    【讨论】:

      【解决方案4】:

      如果您的文本文件足够小,我建议您改用正则表达式。这正是它旨在做的事情。在我的脑海中,表达式将如下所示:

      (?im)^Name:(.*?)$ ^Contact:search_term$^Product:(.*?)$^Quantity:(.*?)$
      

      【讨论】:

      • 我真的很想远离正则表达式。我讨厌尝试使用它们
      • 他知道问题可以通过使用正则表达式来解决。现在他遇到了一个新问题。 ;-)
      猜你喜欢
      • 2011-07-07
      • 2010-12-19
      • 2011-03-02
      • 2011-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多