Get array object by description in index

Asked

Viewed 212 times

4

It is possible to use the property of an object as an index of a array, as described in the example below?

using System;

public class Program
{
    public static void Main()
    {
        var myObjectArray = new MyObject[]{
            new MyObject("item1", "valor1", 1, 1.1),
            new MyObject("item2", "valor2", 2, 2.2),
            new MyObject("item3", "valor3", 3, 3.3)
        };

        // Para obter o valor do objeto com o Name "item2", preciso encontra-lo através do índice:
        Console.WriteLine(myObjectArray[1].Value);

        // O que eu gostaria de fazer é passar o valor da propriedade 'Name' de um determinado objeto como index, 
        // e poder acessar todas as propriedades dele, da seguinte forma:
        Console.WriteLine(myObjectArray["item2"].Value);
    }
}

public class MyObject {
    public string Name {get; set;}
    public string Value {get; set;}
    public int Prop1 {get; set;}
    public double Prop2 {get; set;}

    public MyObject (string name, string valueParam, int prop1, double prop2){
        this.Name = name;
        this.Value = valueParam;
        this.Prop1 = prop1;
        this.Prop2 = prop2;
    }
}

dotnetfiddle

  • Needs to be array or can you change the data structure used? Do the elements in it need to be in a specific order? Can you have repeated elements in the first member of the object? You can separate that member from the rest of the object?

  • Use a data dictionary

  • I have a preference for array, but if that’s not possible, I can consider other options as well. Well, I don’t currently need the elements in specific order, but is there any solution that makes it possible to sort them? I didn’t understand the last questions @Maniero

  • How could I use a data dictionary in this case @Virgilionovic ?

  • 1

    @Jedaiasrodrigues I made an example...

5 answers

4


It seems to me that a dictionary is enough for what you need.

using System;
using System.Collections.Generic;

public class Program {
    public static void Main() {
        var dicionario = new Dictionary<string, MyObject> {
            ["item1"] = new MyObject("item1", "valor1", 1, 1.1),
            ["item2"] = new MyObject("item2", "valor2", 2, 2.2),
            ["item3"] = new MyObject("item3", "valor3", 3, 3.3)
        };
        Console.WriteLine(dicionario["item2"].Value);
    }
}

public class MyObject {
    public string Name {get; set;}
    public string Value {get; set;}
    public int Prop1 {get; set;}
    public double Prop2 {get; set;}

    public MyObject (string name, string valueParam, int prop1, double prop2){
        this.Name = name;
        this.Value = valueParam;
        this.Prop1 = prop1;
        this.Prop2 = prop2;
    }
}

Behold working in the ideone. And in the .NET Fiddle. Also put on the Github for future reference.

The dictionary has access time virtually identical to that of the array, (at least the complexity of access is essentially the same (O(1) in typical case, but O(n) in worst case, which in practice never comes close to happening).

It is important to note that if you have all the elements listed they can come in any order and if you try to take an element by its index it may not see what you are expecting, the algorithm is not stable to give this possibility, even if it works on a basic test, will not work in another case, and the same test that worked may not work anymore if you change the Dictionary or the algorithm of hash of the object used as key. There is no guarantee of anything.

If you need order use a SortedDictionary. It is slightly slower, but in most cases changes very little and there are many cases that it may be faster than the dictionary. It has O(log n) complexity that is very close to O(1). There are cases that the formula of hash may add overhaed that makes it worse than access to the tree of SortedDictionary. His worst case is O(log n), so he is much more predictable and avoids certain types of DOS attacks than the hash allows. And because of the location of reference impaired the table hash of Dictionary can access the data more slowly by not enjoying the cache well.

If you have to ensure that key values do not recur can use a Set, have a few options.

There is another option, the KeyedCollection which gives you the advantage of the list and the advantage of the dictionary at the same time, perhaps it is the most suitable for what you want. It uses one of the members of the object as key implicitly.

  • Thanks @Maniero I didn’t know the Dictionary, and I also really liked your code, it’s very clean and structured, congratulations!

  • The option of SortedDictionary was great! I’ll definitely use this.

  • 1

    @Jedaiasrodrigues note that SortedDictionary is a red-black tree implementation in most cases. Access is worst that a normal dictionary and end up losing performance to insert and to delete elements. The option is good, of course. But it is necessary to be careful when choosing.

  • @LINQ more or less, I improved the text to explain this. Have a problem in your answer, read my current.

  • 1

    @Jedaiasrodrigues put another option. That last question in my comment was about this, in the case of the normal dictionary the key becomes redundant.

2

What you’re looking for is a data structure called Dictionary, she is nothing but a table hash.

A table hash is a linear data structure with constant access complexity, so there is not much loss of performance when changing a array by a dictionary. The access of both is complex O(1). It is clear that the insertion in a table hash is longer than inserting directly into a array, however, using a dictionary there is the advantage of searching for the keys, which are previously defined by you.

You can take advantage of Linq extension methods and do an access through index, as your first example asks.

Note that there is no guarantee that the order of the structure is the same insertion order, because the Dictionary maintains its own order.

Take an example::

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    public static void Main()
    {
        var dicionario = new Dictionary<string, MyObject>()
        {
            { "item1", new MyObject{ Name = "item1", Value = "valor1" } },
            { "item2", new MyObject{ Name = "item2", Value = "valor2" } },
            { "item3", new MyObject{ Name = "item3", Value = "valor3" } }               
        };      

        // Acesso por index:
        Console.WriteLine(dicionario.Values. ElementAt(1));

        // Acesso pela chave
        Console.WriteLine(dicionario["item2"].Value);
    }
}

public class MyObject 
{
    public string Name {get; set;}
    public string Value {get; set;}
    public int Prop1 {get; set;}
    public double Prop2 {get; set;} 
}
  • Thank you @LINQ I didn’t know the Dictionary. He really will take good care of me, and thank you also for already giving me details about him.

2

It is possible to use the property of an object as the index of an array, as described in the example below?

YES

I like working with Collection List better. I find it more elegant, and do not need to create an "Inline" as in the dictionary, you can use the name of your own object, or the ID, as you prefer.

using System;
using System.Collections.Generic;
using System.Linq;
                    
public class Program
{
    public static void Main()
    {
        var minhaColecao = new MinhaCollection();
        minhaColecao.Add(new MeuObjeto { Nome = "A", Valor = 10.0m, Data = DateTime.Now });
        minhaColecao.Add(new MeuObjeto { Nome = "B", Valor = 2.0m, Data = DateTime.Now });
        minhaColecao.Add(new MeuObjeto { Nome = "C", Valor = 340.5m, Data = DateTime.Now });
    
        var objA = minhaColecao["A"];    
    
        Console.WriteLine($"Nome: {objA.Nome} Valor: {objA.Valor} ");
    }
}

public class MinhaCollection : List<MeuObjeto>
{
    public MeuObjeto this[string nome]
    {
        get
        {
            return this.FirstOrDefault(meuObjeto => meuObjeto.Nome == nome);
        }
    }
}

public class MeuObjeto
{
    public string Nome { get; set; }
    public decimal Valor { get; set; }
    public DateTime Data { get; set; }
}

See working on .NET Fiddle.

  • 1

    In this case you go from constant search complexity to linear complexity. A bad solution for those who care about search performance. Although, I find a much better solution for normal cases.

  • 1

    The question is "how to use an object’s property as an array index". This is what I showed you how to do. And another, this is an abstraction, can be used with Dictionary tbm.

  • Interesting option, I liked being able to implement the way you want the method get, but this issue of performance cited by @LINQ is important, I still do not have enough basis to talk about it, but I will be researching. Thank you very much for your reply.

  • Thiago, I read what the question says. I left my comment so that people who arrive here have notion of this, not to criticize. I even said that I find a great solution for most simple everyday cases (including, many Winforms implementations make use of this). About being an abstraction: even if you try to do the implementation with IDictionary the performance will remain the same, is not the presence or absence of a keyword that brings performance and yes the implementation. It is quite possible to implement List and have constant access as in a Hashtable.

2

The easiest would be to add a reference to Linq

using System.Linq;

And make the query according to the attribute you want.

Console.WriteLine(myObjectArray.FirstOrDefault(x => x.Name == "item2").Value);

1

Do with Dictionary, example:

Base Class:

public class MyObject 
{
    public string Name {get; set;}
    public string Value {get; set;}
    public int Prop1 {get; set;}
    public double Prop2 {get; set;}

    public MyObject (string name, string valueParam, int prop1, double prop2)
    {
        this.Name = name;
        this.Value = valueParam;
        this.Prop1 = prop1;
        this.Prop2 = prop2;
    }
}

Dictionary

Dictionary<string, MyObject> myObjectArray = new Dictionary<string, MyObject>();
myObjectArray.Add("Item1", new MyObject("item1", "valor1", 1, 1.1));
myObjectArray.Add("Item2", new MyObject("item2", "valor2", 2, 2.2));
myObjectArray.Add("Item3", new MyObject("item3", "valor3", 3, 3.3));

Recuperating

var dado = myObjectArray["Item1"]

Accessing values:

dado.Name
dado.Value
dado.Prop1
dado.Prop2

AN ONLINE EXAMPLE which can be used as a basis in your code.

References

  • Thank you @Virgilionovic I didn’t know the Dictionary. Really he’ll take good care of me.

  • @Jedaiasrodrigues Vlw

Browser other questions tagged

You are not signed in. Login or sign up in order to post.