Как получить доступ к ссылочным значениям HashSet <TValue>без перечисления? - PullRequest
7 голосов
/ 03 сентября 2011

У меня есть такой сценарий, в котором сохранение памяти имеет первостепенное значение.Я пытаюсь прочитать в> 1 ГБ пептидных последовательностей в память и сгруппировать экземпляры пептидов вместе, которые имеют одну и ту же последовательность.Я храню объекты пептидов в хэше, чтобы я мог быстро проверить на дублирование, но обнаружил, что вы не можете получить доступ к объектам в наборе, даже зная, что набор содержит этот объект.

Память действительно важнаи я не хочу дублировать данные, если это вообще возможно.(В противном случае я бы спроектировал мою структуру данных как: peptides = Dictionary<string, Peptide>, но это дублировало бы строку как в словаре, так и в классе пептидов).Ниже приведен код, демонстрирующий, чего я хотел бы достичь:

public SomeClass {

       // Main Storage of all the Peptide instances, class provided below
       private HashSet<Peptide> peptides = new HashSet<Peptide>();

       public void SomeMethod(IEnumerable<string> files) {
            foreach(string file in files) {
                 using(PeptideReader reader = new PeptideReader(file)) {
                     foreach(DataLine line in reader.ReadNextLine()) {
                         Peptide testPep = new Peptide(line.Sequence);
                         if(peptides.Contains(testPep)) {

                            // ** Problem Is Here **
                            // I want to get the Peptide object that is in HashSet
                            // so I can add the DataLine to it, I don't want use the
                            // testPep object (even though they are considered "equal")
                            peptides[testPep].Add(line); // I know this doesn't work

                            testPep.Add(line) // THIS IS NO GOOD, since it won't be saved in the HashSet which i use in other methods.

                         } else {
                            // The HashSet doesn't contain this peptide, so we can just add it
                            testPep.Add(line);
                            peptides.Add(testPep);
                         }
                     }   
                 }
            }
       }
}

public Peptide : IEquatable<Peptide> {
     public string Sequence {get;private set;}
     private int hCode = 0;

     public PsmList PSMs {get;set;}

     public Peptide(string sequence) {
         Sequence = sequence.Replace('I', 'L');
         hCode = Sequence.GetHashCode();             
     }

     public void Add(DataLine data) {
         if(PSMs == null) {
             PSMs = new PsmList();
         } 
         PSMs.Add(data);
     }

     public override int GethashCode() {
         return hCode;
     }

     public bool Equals(Peptide other) {
         return Sequence.Equals(other.Sequence);
     }
}

public PSMlist : List<DataLine> { // and some other stuff that is not important }

Почему HashSet не позволяет мне получить ссылку на объект, который содержится в HashSet?Я знаю, что люди попытаются сказать, что если HashSet.Contains() вернет true, ваши объекты эквивалентны.Они могут быть эквивалентны с точки зрения значений, но мне нужно, чтобы ссылки были одинаковыми, так как я храню дополнительную информацию в классе пептидов.

Единственное решение, которое я нашел, - это Dictionary<Peptide, Peptide>, в котором ключ и значение указывают на одну и ту же ссылку.Но это кажется липким.Есть ли другая структура данных для этого?

Ответы [ 2 ]

9 голосов
/ 03 сентября 2011

В принципе, вы могли бы переопределить HashSet<T> сами, но это единственное решение, которое я знаю. Решение Dictionary<Peptide, Peptide> или Dictionary<string, Peptide>, вероятно, не , что неэффективно, хотя - если вы тратите только одну ссылку на запись, я бы предположил, что это будет относительно незначительным.

На самом деле, если вы удалите элемент hCode из Peptide, это сохранит вам 4 байта на объект, размер которого в любом случае равен размеру ссылки в x86 ... нет смысла кэшировать хеш до как я могу сказать, поскольку вы будете вычислять хеш каждого объекта только один раз, по крайней мере, в коде, который вы показали.

Если вы действительно отчаянно нуждаетесь в памяти, я подозреваю, что вы могли бы сохранить последовательность значительно эффективнее, чем string. Если вы дадите нам больше информации о том, что содержится в последовательности, мы можем внести некоторые предложения там.

Я не знаю, что есть какая-то особенно веская причина , почему HashSet этого не позволяет, за исключением того, что это относительно редкое требование - но это то, что я видел запрошенным в Java как хорошо ...

1 голос
/ 03 сентября 2011

Используйте Dictionary<string, Peptide>.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...