C # Лучший способ сохранить строки из входного файла для манипулирования и использования?

У меня есть файл блоков строк, каждый из которых заканчивается определенным ключевым словом. В настоящее время у меня есть настройка чтения потока, которая добавляет каждую строку файла в список до конца текущего блока (строка содержит ключевое слово, указывающее конец блока).

listName.Add(lineFromFile);

Каждый блок содержит информацию, например, Книга bookName, Author AuthorName, Journal JournalName и т. Д. Таким образом, каждый блок гипотетически представляет собой отдельный элемент (книга, журнал, конференция и т. Д.).

Теперь, имея около 50 или около того блоков информации (элементов), мне нужен какой-то способ хранения информации, чтобы я мог манипулировать ею и хранить каждого автора (ов), заголовок, страницы и т. Д. И знать, какая информация идет с каким элементом и т. Д.

Набирая это, я пришел к мысли о том, чтобы, возможно, сохранить каждый элемент как объект класса с именем «Item», однако с потенциально несколькими авторами я не уверен, как этого добиться, так как я думал, может быть, использовать счетчик для имени переменной, например

int i = 0;
String Author[i] = "blahblah";
i++;

Но насколько я знаю, это запрещено? Итак, мой вопрос в основном заключается в том, что было бы самым простым / легким способом сохранить каждый элемент, чтобы я мог манипулировать строками для сохранения каждого элемента для использования позже.

@yamen вот пример файла:

Author Bond, james
Author Smith John A
Year 1994
Title For beginners
Book Accounting
Editor Smith Joe
Editor Doe John
Publisher The University of Chicago Press
City Florida, USA
Pages 15-23
End

Author Faux, M
Author Sedge, M
Author McDreamy, L
Author Simbha, D
Year 2000
Title Medical advances in the modern world
Journal Canadian Journal of medicine
Volume 25
Pages 1-26
Issue 2
End


Author McFadden, B
Author Goodrem, G
Title Shape shifting dinosaurs
Conference Ted Vancouver
City Vancouver, Canada
Year 2012
Pages 2-6
End

person ShaneL    schedule 15.05.2012    source источник
comment
Можете показать пример файла?   -  person yamen    schedule 15.05.2012
comment
@yamen Добавил пример кода в исходный пост ^   -  person ShaneL    schedule 15.05.2012


Ответы (8)


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

using System;
using System.Collections.Generic;
using System.IO;

namespace MutiItemDict
{
    class MultiDict<TKey, TValue>  // no (collection) base class
    {
        private Dictionary<TKey, List<TValue>> _data = new Dictionary<TKey, List<TValue>>();

        public void Add(TKey k, TValue v)
        {
            // can be a optimized a little with TryGetValue, this is for clarity
            if (_data.ContainsKey(k))
                _data[k].Add(v);
            else
                _data.Add(k, new List<TValue>() { v });
        }

        public List<TValue> GetValues(TKey key)
        {
            if (_data.ContainsKey(key))
                return _data[key];
            else
                return new List<TValue>();
        }
    }

    class BookItem
    {
        public BookItem()
        {
            Authors = new List<string>();
            Editors = new List<string>();
        }

        public int? Year { get; set; }
        public string Title { get; set; }
        public string Book { get; set; }
        public List<string> Authors { get; private set; }
        public List<string> Editors { get; private set; }
        public string Publisher { get; set; }
        public string City { get; set; }
        public int? StartPage { get; set; }
        public int? EndPage { get; set; }
        public int? Issue { get; set; }
        public string Conference { get; set; }
        public string Journal { get; set; }
        public int? Volume { get; set; }

        internal void AddPropertyByText(string line)
        {
            string keyword = GetKeyWord(line);
            string data = GetData(line);
            AddData(keyword, data);
        }

        private void AddData(string keyword, string data)
        {
            if (keyword == null)
                return;

            // Map the Keywords to the properties (can be done in a more generic way by reflection)
            switch (keyword)
            {
                case "Year":
                    this.Year = int.Parse(data);
                    break;
                case "Title":
                    this.Title = data;
                    break;
                case "Book":
                    this.Book = data;
                    break;
                case "Author":
                    this.Authors.Add(data);
                    break;
                case "Editor":
                    this.Editors.Add(data);
                    break;
                case "Publisher":
                    this.Publisher = data;
                    break;
                case "City":
                    this.City = data;
                    break;
                case "Journal":
                    this.Journal = data;
                    break;
                case "Volume":
                    this.Volume = int.Parse(data);
                    break;
                case "Pages":
                    this.StartPage = GetStartPage(data);
                    this.EndPage = GetEndPage(data);
                    break;
                case "Issue":
                    this.Issue = int.Parse(data);
                    break;
                case "Conference":
                    this.Conference = data;
                    break;
            }
        }

        private int GetStartPage(string data)
        {
            string[] pages = data.Split('-');
            return int.Parse(pages[0]);
        }

        private int GetEndPage(string data)
        {
            string[] pages = data.Split('-');
            return int.Parse(pages[1]);
        }

        private string GetKeyWord(string line)
        {
            string[] words = line.Split(' ');
            if (words.Length == 0)
                return null;
            else
                return words[0];
        }

        private string GetData(string line)
        {
            string[] words = line.Split(' ');
            if (words.Length < 2)
                return null;
            else
                return line.Substring(words[0].Length+1);
        }
    }

    class Program
    {
        public static BookItem ReadBookItem(StreamReader streamReader)
        {
            string line = streamReader.ReadLine();
            if (line == null)
                return null;

            BookItem book = new BookItem();
            while (line != "End")
            {
                book.AddPropertyByText(line);
                line = streamReader.ReadLine();
            }
            return book;
        }

        public static List<BookItem> ReadBooks(string fileName)
        {
            List<BookItem> books = new List<BookItem>();
            using (StreamReader streamReader = new StreamReader(fileName))
            {
                BookItem book;
                while ((book = ReadBookItem(streamReader)) != null)
                {
                    books.Add(book);
                }
            }
            return books;
        }

        static void Main(string[] args)
        {
            string fileName = "../../Data.txt";
            List<BookItem> bookList = ReadBooks(fileName);

            MultiDict<string, BookItem> booksByAutor = new MultiDict<string, BookItem>();
            bookList.ForEach(bk =>
                    bk.Authors.ForEach(autor => booksByAutor.Add(autor, bk))
                );

            string author = "Bond, james";
            Console.WriteLine("Books by: " + author);
            foreach (BookItem book in booksByAutor.GetValues(author))
            {
                Console.WriteLine("    Title : " + book.Title);
            }

            Console.WriteLine("");
            Console.WriteLine("Click to continue");
            Console.ReadKey();
        }
    }
}

И я также хочу упомянуть, что всего этого можно избежать, если вы представляете данные в XML. Тогда данные выглядят так:

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfBookItem >
  <BookItem>
    <Year>1994</Year>
    <Title>For beginners</Title>
    <Book>Accounting</Book>
    <Authors>
      <string>Bond, james</string>
      <string>Smith John A</string>
    </Authors>
    <Editors>
      <string>Smith Joe</string>
      <string>Doe John</string>
    </Editors>
    <Publisher>The University of Chicago Press</Publisher>
    <City>Florida, USA</City>
    <StartPage>15</StartPage>
    <EndPage>23</EndPage>
  </BookItem>
  <BookItem>
    <Year>2000</Year>
    <Title>Medical advances in the modern world</Title>
    <Authors>
      <string>Faux, M</string>
      <string>Sedge, M</string>
      <string>McDreamy, L</string>
      <string>Simbha, D</string>
    </Authors>
    <StartPage>1</StartPage>
    <EndPage>26</EndPage>
    <Issue>2</Issue>
    <Journal>Canadian Journal of medicine</Journal>
    <Volume>25</Volume>
  </BookItem>
  <BookItem>
    <Year>2012</Year>
    <Title>Shape shifting dinosaurs</Title>
    <Authors>
      <string>McFadden, B</string>
      <string>Goodrem, G</string>
    </Authors>
    <City>Vancouver, Canada</City>
    <StartPage>2</StartPage>
    <EndPage>6</EndPage>
    <Conference>Ted Vancouver</Conference>
  </BookItem>
</ArrayOfBookItem>

И код для его чтения:

using (FileStream stream =
    new FileStream(@"../../Data.xml", FileMode.Open,
        FileAccess.Read, FileShare.Read))
        {
            List<BookItem> books1 = (List<BookItem>)serializer.Deserialize(stream);
        }
person Tal Segal    schedule 17.05.2012
comment
Это для университетской проблемы, поэтому я буду ссылаться только на код, который вы мне дали, чтобы получить представление о методе, который вы использовали для выполнения задач, и попытаюсь переписать его по-другому, но это очень очень полезно и на уровне, который я могу понять. Я проголосую за это как за лучший ответ, поскольку он написан на понятном мне уровне и довольно прост, но выполняет свою работу. Большое спасибо за вашу помощь! - person ShaneL; 17.05.2012
comment
@ShaneL - Спасибо, это то, что я пытался сделать, и именно так я пытаюсь написать большую часть своего кода - Просто и понятно, это лучше всего для обслуживания. - person Tal Segal; 17.05.2012
comment
И ваш второй пример - прекрасный пример того, почему людей, изобретающих собственные форматы файлов, нужно избивать большой палкой и заставлять использовать либо XML, либо JSON. - person Peter Wone; 18.05.2012
comment
@TalSegal Привет, приятель, просто прочитал твой код, и эта часть меня озадачила, есть ли шанс, что ты сможешь интерпретировать это мне? MultiDict<string, BookItem> booksByAutor = new MultiDict<string, BookItem>(); bookList.ForEach(bk => bk.Authors.ForEach(autor => booksByAutor.Add(autor, bk)) ); - person ShaneL; 18.05.2012
comment
@ShaneL - этот синтаксис называется Linq. Я вставил сюда две петли. Вы можете заменить его на: foreach (book in booklist) { foreach (author in book.Authors) { booksByAutor.Add(autor, book); } } Вы можете прочитать о Linq здесь: msdn.microsoft. ru / en-us / library / bb397933.aspx - person Tal Segal; 19.05.2012
comment
Я в основном перебираю все книги и в каждой книге перебираю всех авторов и вставляю их в словарь. - person Tal Segal; 19.05.2012
comment
@TalSegal Ах, да, вчера вечером я провел некоторое время, исследуя лямбда-выражение = ›, довольно сложно. Спасибо за пример Foreach, он намного проще для понимания. Ваше здоровье. Жаль, что здесь нет Pm'ing, было бы намного проще - person ShaneL; 19.05.2012
comment
@ShaneL - если хотите, можете написать мне на почту - [email protected] - person Tal Segal; 19.05.2012
comment
@TalSegal Хорошо, если у меня возникнут другие вопросы, я напишу вам электронное письмо - person ShaneL; 19.05.2012
comment
@ShaneL - Если это то, чему может научиться больше людей (а все остальные ваши вопросы были такого рода) - тогда это подходящее место, чтобы задавать вопросы и получать ответы, а также помогать другим людям также извлекать из этого пользу. В любом случае, мне всегда приятно помочь. - person Tal Segal; 19.05.2012

Обновление вместо образца

Как разобрать строку выходит за рамки этого ответа - вы можете попробовать это самостоятельно, а затем спросить другого SO (я предлагаю прочитать золотые правила SO:

Итак, я представлю решение, предполагая, что у вас есть одна строка, представляющая полный блок информации о книге / журнале (эти данные выглядят как цитаты). Основное отличие от моего первоначального ответа заключается в том, что у вас несколько авторов. Также вы можете подумать, хотите ли вы преобразовать имена авторов обратно в [first name/initial] [middle names] [surname].

Я представляю два решения - одно с использованием Dictionary и одно с использованием Linq. Решение Linq является однострочным.

Определите класс Info для хранения элемента:

public class Info
{
   public string Title { get; private set; }
   public string BookOrJournal { get; private set; }
   public IEnumerable<string> Authors { get; private set; }
   //more members of pages, year etc.
   public Info(string stringFromFile)
   {
     Title = /*read book name from stringFromFile */;
     BookOrJournalName = /*read journal name from stringFromFile */;
     Authors = /*read authors from stringFromFile */;
   }
}

Обратите внимание, что stringFromFile должен быть одним блоком, включая новые строки, информации о цитировании.

Теперь словарь для хранения каждой информации по автору:

Dictionary<string, List<Info>> infoByAuthor = 
  new Dictionary<string, List<Info>>(StringComparer.OrdinalIrgnoreCase);

Обратите внимание на OrdinalIgnoreCase компаратор - для обработки ситуаций, когда имя автора печатается в другом регистре.

Учитывая List<string>, который вы добавляете в соответствии с вашим listName.Add, этот простой цикл поможет:

List<Info> tempList;
Info tempInfo;
foreach(var line in listName)
{
  if(string.IsNullOrWhiteSpace(line))
    continue;
  tempInfo = new Info(line);
  foreach(var author in info.Authors)
  {
    if(!infoByAuthor.TryGetValue(author, out tempList))
      tempInfo[author] = tempList = new List<Info>();
    tempList.Add(tempInfo);
  }
}

Теперь вы можете перебирать словарь, и каждый KeyValuePair<string, List<Info>> будет иметь Key, равный имени автора, а Value будет списком Info объектов, имеющих этого автора. Обратите внимание, что регистр AuthorName будет сохранен из файла, даже если вы группируете без учета регистра, так что два элемента с "jon skeet" и "Jon Skeet" будут сгруппированы в один и тот же список, но их исходные регистры будут сохранены в Info.

Также код написан, чтобы гарантировать, что для каждой ссылки создается только один Info экземпляр, это предпочтительно по многим причинам (память, централизованные обновления и т. Д.).

В качестве альтернативы вы можете просто сделать это с помощью Linq:

var grouped = listName.Where(s => !string.IsNullOrWhiteSpace(s))
  .Select(s => new Info(s))
  .SelectMany(i => 
    s.Authors.Select(ia => new KeyValuePair<string, Info>(ia, i))
  .GroupBy(kvp => kvp.Key, kvp => kvp.Value, StringComparer.OrdinalIgnoreCase);

Теперь у вас есть список групп, где Key - это имя автора, а внутреннее перечисляемое - это все Info объекты с этим именем автора. То же самое поведение с сохранением регистра в отношении «двух скитов» будет наблюдаться и здесь.

person Andras Zoltan    schedule 15.05.2012
comment
Я добавил образец файла к основному посту для большей ясности, сейчас я просто исследую словари, чтобы понять, что вы говорите, поскольку я никогда не слышал о словарях данных и никогда не использовал цикл foreach в этом отношении ...;) . Ты определенно знаешь свое дело, хотя - person ShaneL; 15.05.2012
comment
@ShaneL, хорошо, обновил мой ответ - обратите внимание, я не собираюсь рассказывать вам, как разбирать строку; это слишком похоже на написание всей программы за вас :) - person Andras Zoltan; 15.05.2012
comment
Большое спасибо, да, я только изначально ожидал ответа вроде: взгляните на словари данных и / или вы должны создать класс информации, как вы показали. Я высоко ценю толчок в этом направлении, надеюсь, поможет мне пройти мой трехдневный блок программирования, в котором я пытался найти ответ на мою проблему :) - person ShaneL; 16.05.2012

Вы должны создать класс Book

public class Book
 {
    public string Name { get; set; }
    public string Author { get; set; }
    public string Journal { get; set; }

 }

и поддерживать List<Book>

var books = new List<Book>();
books.Add(new Book { Name = "BookName", Author = "Some Auther", Journal = "Journal" });
person Asif Mushtaq    schedule 15.05.2012
comment
Ваш ответ семантически более элегантен, но когда некоторые строки пусты или не имеют некоторых значений, вам нужно продолжать увеличивать логику конструктора и добавлять null-s вместо пустых строк. - person Luka Ramishvili; 15.05.2012

Я бы использовал для этого многозначный словарь:

public struct BookInfo
    {
        public string Title;
        public string Journal;
    }

Затем создайте объект словаря:

var dict = new Dictionary<Author, BookInfo>();

Таким образом, если вы столкнетесь с несколькими авторами, данные будут отсортированы по авторам, что упростит написание будущего кода для работы с этими данными. Распечатать список всех книг под некоторым автором будет очень просто и не потребует громоздкого процесса поиска.

person Colin Docherty    schedule 15.05.2012
comment
Таким образом, вы ограничиваете каждого автора только одной книгой, что не дает вам возможности перечислить все книги, потому что это только одна книга. - person Luka Ramishvili; 15.05.2012

Вы можете использовать класс с такими простыми атрибутами, как эти:

class Book {
    string Title;
    int PageCount;
}

Вы можете либо инициализировать Book[] lines = Book[myFile.LineCount];, либо поддерживать List<Book>, но строка [] упрощает доступ к отдельным номерам строк (lines[34] означает 34-ю книгу и 34-ю строку).

Но в основном System.Data.DataTable может быть лучше подходящим, потому что у вас есть строки, содержащие несколько столбцов. С помощью DataTable вы можете получить доступ к отдельным строкам и получить доступ к их столбцам по имени.

Пример:

DataTable dt = new DataTable();
DataTable.Columns.Add("bookName");

DataRow dr = dt.NewRow();
dr["bookName"] = "The Lost Island";
dt.Rows.Add(dr);

//You can access last row this way: 
dt.Rows[dt.Rows.Count-1]["bookName"].

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

Изменить: Изначально в моем ответе использовались структуры, но, как указал @AndrasZoltan, может быть лучше использовать классы, если вы не уверены, во что будет развиваться приложение.

person Luka Ramishvili    schedule 15.05.2012
comment
struct здесь не имеет реального применения. Также List ‹› предлагает ту же индексацию, что и массив. - person Andras Zoltan; 15.05.2012
comment
Вы можете указать, почему нет? Потому что у него есть. Массив структур. Это сложно проглотить? - person Luka Ramishvili; 15.05.2012
comment
Вы можете использовать и классы и структуры, потому что OP не нужны методы. - person Luka Ramishvili; 15.05.2012
comment
Отличная точка; но, тем не менее, структуры можно использовать без проблем. Однако в долгосрочной перспективе класс будет лучшим подходом, если приложение будет расти. До этого всегда соблазнительно раздувать код класса (и, конечно, это зависит от программиста). - person Luka Ramishvili; 15.05.2012
comment
'структуры можно использовать без проблем' - как насчет того, чтобы он изменялся или должен быть много прошло? Решение использовать структуру не зависит от того, сколько кода в нее входит (Microsoft предлагает, чтобы в MSDN было проще принять решение для людей, которые не хотят знать полные детали), все зависит от того, эффективнее ли сохранить данные, хранящиеся в памяти. - person Andras Zoltan; 15.05.2012
comment
Я рассмотрел ситуацию OP, когда сказал, что можно использовать трюки. В упомянутых вами ситуациях или если OP сталкивается с подобной ситуацией, правильно, классы - лучший подход. А он может избавить его от головной боли и сразу выбрать его. - person Luka Ramishvili; 15.05.2012
comment
@Luka Ramishvili Хм, вижу кучу новых терминов, которых никогда раньше не видел. например Таблицы данных. Мне нужно немного изучить, подходит ли он для того, что мне нужно. В основном необходимо манипулировать входным файлом для создания intext и полной библиографической ссылки и отображать их в списке и текстовом поле соответственно (наряду с некоторыми другими функциями, такими как нажатие на каждую ссылку в тексте, отображается ее полнотекстовая ссылка в текстовом поле и т. Д.) - person ShaneL; 15.05.2012
comment
@ShaneL Я думаю, что лучше всего записать структуру вашей программы на бумаге (или в текстовом документе), а затем построить на ее основе лучшую структуру. Я думаю, вам следует использовать классы и создать крошечный API (например, public Book[] FindBooksOfAuthor(string AuthorName){...} и public Author AuthorOfBook(string BookName){..}. Я также предлагаю перейти на реляционную базу данных (например, MySQL) для хранения данных, это упростит разработку. - person Luka Ramishvili; 15.05.2012
comment
@ Лука Рамишвили Спасибо за помощь и совет, очень признателен - person ShaneL; 16.05.2012
comment
@ShaneL Нет проблем, я рада, если это хоть немного помогло. - person Luka Ramishvili; 16.05.2012
comment
@AndrasZoltan (вы отредактировали четвертый комментарий, отвечая на него) Думаю, нет, подозреваю, что я больше привык к структурам C и говорил с этой точки зрения. Я помню, что раньше читал эту статью о структурах C #, но, видимо, я не помнил, что в ней говорилось :)) - person Luka Ramishvili; 16.05.2012
comment
@AndrasZoltan Возможно, чтобы лучше выразить свою точку зрения, я имел в виду не методы напрямую, а объектно-ориентированный подход. Но, как мы договорились, в конечном итоге классы лучше и более расширяемы. - person Luka Ramishvili; 16.05.2012

Вы на правильном пути к созданию реляционной базы данных. Удобно, что они уже доступны. Помимо решения проблемы хранения отношений между сущностями, они также решают проблемы параллелизма и поддерживаются методами моделирования, основанными на доказуемой математике.


Парсеры являются предметом самих себя. Поскольку о SQL не может быть и речи, это надуманное университетское задание, у меня есть некоторые наблюдения.

  • Простой способ - использовать регулярное выражение. Однако это крайне неэффективно и плохое решение для больших входных файлов.
  • В отсутствие регулярных выражений String.IndexOf () и String.Split () - ваши друзья.
  • Если ваш оценщик не может справиться с SQL, то LINQ будет настоящим шоком, но мне очень нравится решение Zoltan LINQ, оно просто элегантно.
person Peter Wone    schedule 15.05.2012
comment
Я подумал об ответе аналогичным образом: «используйте SQL Express» или что-то в этом роде. Есть большая вероятность, что этот файл можно просто пропустить через пакет SSIS. - person Andras Zoltan; 15.05.2012
comment
@Peter Wone, я думаю, что моя формулировка вопроса могла быть немного неясной, в основном меня просто просят взять входной файл и создать текст и полные ссылки. однако фактический справочный файл не так хорош, как тот, который я предоставил, и полон ошибок и т. д. - person ShaneL; 15.05.2012
comment
Итак, вы начинаете с файла, созданного какой-то другой системой, и пытаетесь построить из него объектную модель? - person Peter Wone; 15.05.2012
comment
Нет, по сути, просто создание приложения, в котором пользователь открывает файл в том же формате, что и указанный выше, а затем на основе этого приложение превращает каждую запись в библиографическую ссылку в текстовом стиле для отображения в списке и полной ссылке. для отображения в текстовом поле. Затем, используя стрелки навигации, приложение будет циклически перебирать текстовые ссылки в поле списка и отображать соответствующую полную ссылку в текстовом поле. Надеюсь, это немного яснее. - person ShaneL; 15.05.2012
comment
Если это разработка с нуля, почему формат файла полностью и внешне определен? Это университетское задание? - person Peter Wone; 16.05.2012
comment
@Peter Wone Да, это университетское задание, однако учитель ранее заметил, что он очень мало понимает SQL, поэтому мне не хотелось бы обременять его попытками понять мой код, если мои комментарии не объясняют это четко. Я был только после легкого толчка в том направлении, которое было бы проще, например. DataDictionaries вместе с классом INFO, здесь определенно много полезной информации. - person ShaneL; 16.05.2012

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

public IList<Entry> ParseEntryFile(string fileName)
{
    ...
    var entries = new List<Entry>();

    foreach(var line in file)
    {
        var entry = new Entry();
        ...
        entries.Add(entry);
    }
    return entries;
}


public class Entry
{
    public Book BookEntry { get; set; }
    public Author AuthorEntry { get; set; }
    public Journal JournalEntry { get; set; }
}

public class Book
{
    public string Name{ get; set; }
    ...
}

public class Author
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

...
person Bronumski    schedule 15.05.2012
comment
В исходное сообщение добавлен образец входного файла для дальнейшего пояснения. Мне просто нужно манипулировать данными, чтобы формировать текстовые и полные ссылки и отображать их в списке и текстовом поле соответственно. - person ShaneL; 15.05.2012

Вы можете создать класс для каждого элемента:

class BookItem
        {
            public string Name { get; set; }
            public string Author { get; set; }
        }

Считайте данные из каждой строки в экземпляр этого класса и сохраните их во временном списке:

var books = new List<BookItem>();
while (NotEndOfFile())
{
    BookItem book= ReadBookItem(...)
    books.Add(book);
}

После того, как у вас есть этот список, вы можете создавать многозначные словари и иметь быстрый доступ к любому элементу с помощью любой клавиши. Например, чтобы найти книгу по автору:

var booksByAuthor = new MultiDict<string, BookItem>();

добавить элементы в Словарь:

books.ForEach(bk => booksByAuthor.Add(bk.Author, bk));

а затем вы можете повторить его:

string autorName = "autor1";
Console.WriteLine("Books by: " + autorName);
            foreach (BookItem bk1 in booksByAutor)
            {
                Console.WriteLine("Book: " + bk1.Name);
            }

Я получил базовый словарь нескольких предметов отсюда:

Многозначный словарь?

Это моя реализация:

class MultiDict<TKey, TValue>  // no (collection) base class
        {
            private Dictionary<TKey, List<TValue>> _data = new Dictionary<TKey, List<TValue>>();

            public void Add(TKey k, TValue v)
            {
                // can be a optimized a little with TryGetValue, this is for clarity
                if (_data.ContainsKey(k))
                    _data[k].Add(v);
                else
                    _data.Add(k, new List<TValue>() { v });
            }

            // more members

            public List<TValue> GetValues(TKey key)
            {
                if (_data.ContainsKey(key))
                    return _data[key];
                else
                    return new List<TValue>();
            }

        }
person Tal Segal    schedule 15.05.2012
comment
На этом этапе мне сложно следовать. Однако с классом для каждого элемента, скажем, если бы в книге было более 1 автора, разве я не столкнулся бы с проблемами со следующим? code class BookItem { public string Name { get; set; } public string Author { get; set; } } - person ShaneL; 15.05.2012
comment
Я предполагал, что у вас есть только один автор на книгу. Если вам нужно несколько авторов, я бы использовал этот код: class BookItem { public BookItem() { Authors = new List<string>(); } public string Name { get; set; } public List<string> Authors { get; private set; } } BookItem book = new BookItem { Name = "The Great Contraction", Authors = { "Milton Friedman", "Anna Jacobson Schwartz" } }; - person Tal Segal; 16.05.2012
comment
Похоже, он делает все, что мне нужно, самым упрощенным способом, спасибо большое. Цените помощь! - person ShaneL; 17.05.2012