NiDeep
NiDeep

Reputation: 43

C# Linq question

I have a text file in which I am storing entries for an address book. The layout is like so:

Name:
Contact:
Product:
Quantity:

I have written some linq code to grab the name plus the next four lines, for a search by name feature. I also want to be able to search by contact. The challenge is to match the contact info, grab the next 3 lines, and also grab the line prior to the match. That way if Search By Contact is used, the full list of info will be returned.

  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("");
            }
    }

Upvotes: 1

Views: 154

Answers (4)

seairth
seairth

Reputation: 2062

If your text file is small enough, I'd recommend using regular expressions instead. This is exactly the sort of thing it's designed to do. Off the top of my head, the expression will look something like this:

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

Upvotes: 0

Miguel Angelo
Miguel Angelo

Reputation: 24212

This is not the smallest code in earth but it shows how to do a couple of things. Although I don't recommend using it, because it is quite complex to understand. This is to be considered as a hobbyist, just learning code!!! I suggest you load the file in a well known structure, and do Linq on that... anyway... this is a C# Console Application that does what you proposed using Linq syntax, and one extension method:

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;
        }
    }
}

Upvotes: 0

Paul Creasey
Paul Creasey

Reputation: 28884

Firstly i would recommend changing your data storage approach if you can.

Secondly i would recommend reading the file into an object, something like this:

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;
    ...
}

Upvotes: 4

Bala R
Bala R

Reputation: 109017

See if this will work

 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));

Upvotes: 0

Related Questions