Используя LINQ, как мне найти объект с заданным значением свойства из списка?

У меня есть класс под названием Questions. Этот Questions имеет свойства QuestionID и QuestionAnswer. Повторяя это через List of Question в foreach, я должен найти .QuestionID = 12. Если я нахожу .QuestionID = 12, тогда я должен немедленно присвоить значение .QuestionAnswer = "SomeText" .QuestionID = 14.

Я не хочу снова повторять внутри .QuestionId = 12' to find.QuestionID = 14`.

Можно ли перейти непосредственно к .QuestionID = 14 с помощью LINQ?.

Например:

For Each mQuestion As Question In _mQuestions
    If mQuestion.QuestionId = 12 Then
         'Find mQuestion.QuestionID= 14 and insert Somtext to 
          'mQuestion.QuestionAnswer="SomeText"
    End IF
Next

Ответы

Ответ 1

Я думаю, вы ищете что-то вроде этого. Если у меня есть момент, я переведу его на VB, но я думаю, что вы можете следовать.

if (_mQuestions.Any(q => q.QuestionID == 12)) 
{
   Question question14 = _mQuestions.FirstOrDefault(q => q.QuestionID == 14);
   if (question14 != null)
       question14.QuestionAnswer = "Some Text";
}

Ответ 2

К сожалению, ваша структура данных (List) требует повторного поиска, чтобы найти Question-14 один раз Question-12. Если ваш список Question сортируется по идентификатору, то могут быть сделаны некоторые улучшения, но, как правило, нет способа прямого доступа к элементу List или Array, только зная значения свойства element.

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

Вы можете скрывать свой список в словаре с помощью Linq, вызывая метод расширения ToDictionary():

IDictionary<Question> questions = _mQuestions.ToDictionary(q => q.id);

В качестве ключа используется идентификатор объекта Question, а объект - как значение. Затем в вашем коде вы можете сделать следующее:

if (questions.ContainsKey(12) && questions.ContainsKey(14))
{
    questions[14].QuestionAnswer = "Some Text";
}

Обратите внимание, что ContainsKey и индекс (оператор []) выполняются в постоянное время.

Ответ 3

Имейте в виду, я беру на себя это немного более многословие, чем другие образцы, но мне удалось это сделать только с LINQ. (Следите за комментариями в стиле C ниже!)

Private Shared Sub Main(args As String())
    Dim questions As List(Of Question) = GetQuestions()
    Dim question As Question = ( _
        Where q.ID = 14 AndAlso _
              questions.Exists(Function(p) p.ID = 12)).FirstOrDefault()
    If question IsNot Nothing Then
        question.Answer = "Some Text"
    End If
End Sub



 // Build the collection of questions! We keep this simple.
Private Shared Function GetQuestions() As List(Of Question)
    Dim questions As New List(Of Question)()
    questions.Add(New Question(12, "foo"))
    questions.Add(New Question(14, "bar"))
    Return questions
End Function

// You've already got this class. This one is just my version.
Public Class Question
    Public Sub New(id As Integer, answer As String)
        Me.ID = id
        Me.Answer = answer
    End Sub
    Public Property ID() As Integer
        Get
            Return m_ID
        End Get
        Set
            m_ID = Value
        End Set
    End Property
    Private m_ID As Integer
    Public Property Answer() As String
        Get
            Return m_Answer
        End Get
        Set
            m_Answer = Value
        End Set
    End Property
    Private m_Answer As String
End Class

Ответ 4

Использование LINQ:

var listOfQ = new List<Question>();

// populate the list of Question somehow...

var q14 = listOfQ.FirstOrDefault(q => q.QuestionID == 14);
if (listOfQ.Any(q => q.QuestionID == 12) && q14 != null)
{
    q14.QuestionAnswer = "SomeText";
}