Maro
Maro

Reputation: 2629

Find values in a string

I have a file with lines of string. Each line represent a collection of key value, for example:

Name=JUI;Type=HomeUser;Address=Belgium;Address=Liege;Address=Street
Name=Tim;Type=HomeUser;Address=Belgium;Address=Hasselt;Address=Street
Name=Kim;Type=Proff;Address=Germany;Address=Dusseldorf;Address=Street
Name=Ils;Type=Proff;Address=Germany;Address=Munich;Address=Street
Name=Jan;Type=Student;Address=Germany;Address=Frankfurt;Address=Street
Name=Dav;Type=Student;Address=France;Address=Mitz;Address=Street
Name=Soli;Type=HomeUser;Address=France;Address=Lyon;Address=Street
Name=Mik;Type=HomeUser;Address=Switzerland;Address=Zurich;Address=Street
Name=Peter;Type=Blocked;Address=Netherland;Address=Enschede;Address=Street 
Name=Maz;Type=Blocked;Address=Germany;Address=Achen;Address=Street
Name=Jo;Type=Teacher;Address=Belgium;Address=Antwerpen;Address=Street

How can I do the following:

  1. Get the names where type is HomeUser
  2. Get the types where Address =Germany (problem there are 3 address key in earch line)
  3. Get the name where address =Lyon

Is there is a simple way to do that?

Upvotes: 1

Views: 200

Answers (4)

Eren Ersönmez
Eren Ersönmez

Reputation: 39085

One way to do this is to read the key-value pairs into a collection of dynamic objects. Once this is done, you can use the dynamic runtime to query the dynamic objects using LINQ:

To create a collection of dynamic objects:

var users = str.Split("\r\n".ToArray(), StringSplitOptions.RemoveEmptyEntries)
                .Select(x => x.Split(';')
                    .Select(p => p.Split('='))
                    .ToLookup(s => s[0], s => s[1])
                    .ToDictionary(l => l.Key, l => (l.Count() > 1) 
                        ? (object)l.ToList() : (object)l.First())
                    .ToExpando());

Note the use of this extension method:

public static dynamic ToExpando(this IDictionary<string, object> dict)
{
    IDictionary<string, object> expando = new ExpandoObject();
    foreach (var kv in dict)
        expando[kv.Key] = kv.Value;
    return expando;
}

Then you can run the queries you're interested in:

1.Get the names where type is HomeUser:

var homeUsers = users.Where(u => u.Type == "HomeUser")
    .Select(u => u.Name);

2.Get the types where Address =Germany (Note: .Address is a List<string>):

var typesInGermany = users.Where(u=>u.Address.Contains("Germany"))
    .Select(u => u.Type).Distinct();

3.Get the name where address =Lyon:

var namesInLyon = users.Where(u => u.Address.Contains("Lyon"))
    .Select(u => u.Name);

Upvotes: 0

Nolonar
Nolonar

Reputation: 6122

It would be easier to first define a struct

struct MyStruct
{
    public string Name, Type /* etc.*/ ;
}

After that you'll need to split your input

string[] arrayOfInputs = inpuString.Split(new char[]{Environment.NewLine, '\n', '\r'}) // splits your input, such that every element represents a line
List<MyStruct> myStruct = new List<MyStruct>;
foreach (string s in arrayOfInputs)
{
    string[] arrayOfFields = s.Split(';');
    // arrayOfFields[0] == "Name=name"
    // arrayOfFields[1] == "Type=type"
    // etc. extract needed info
    myStruct.Add(new MyStruct(/* arguments go here */))
}

Now that you have extracted your data and put them into a list of structs, you may search for the required data using Linq

string theNameImLookingFor = from element in myStruct
                             where element.Type == "HomeUser"
                                || element.Address[0] == "Lyon"
                                || element.Address[1] == "Lyon"
                                || element.Address[2] == "Lyon"
                             select element.Name;

string theTypeImLookingFor = from element in myStruct
                             // etc.
                             select element.Type;

Alternatively you can do it like this:

string tNILF = myStruct.Where(element => element.Type == "HomeUser" /* || etc. */).Select(element => element.Name);

Upvotes: 0

Axarydax
Axarydax

Reputation: 16603

Create a Regex to parse the item: "Name=(.+?);Type=(.+?);Address=(.+?) etc." Then you could create a class to hold all the information

class Record { public string Name; public string Type; public string Address; public string Address2; public string Address3}

then match each line with the regex, fill the fields from Match groups and create an instance of the class and add these to a List<Record> records.

Now you can easily search with linq for:

  1. type is HomeUser : records.Where(p=>p.Type=="HomeUser")
  2. Address is Germany : records.Where(p=>p.Address=="Germany")
  3. Address is Lyon: records.Where(p=>p.Address=="Lyon")

you could easily extend this example to look in all 3 address fields

Upvotes: 3

Jon Skeet
Jon Skeet

Reputation: 1499900

In all of these cases, the answer is really simple when you've got a better data representation - you can just use LINQ.

However, the first step will be to parse the data. Model it something like this:

public class User // ???
{
    public string Name { get; private set; }
    public string Type { get; private set; } // Should this be an enum?
    public IList<string> Addresses { get; private set; }

    // Could make this a constructor if you really want... I like the
    // explicit nature of the static factory method.
    public static User ParseLine(string line)
    {
        // TODO: Split line into components etc
    }
}

One you've got a List<User> your queries will be really easy - but it's important to separate "put data into a more natural representation" from "do interesting operations with data".

This is a much more general point than just this particular example, but always try to get your data into a natural, useful representation as early as you can, and then keep it in that representation for as long as you can. Only deal with an awkward representation (typically a string) at the boundaries of your code, if possible.

Upvotes: 4

Related Questions