2010-10-08 21 views
13

Tengo una clase llamada Questions. Este Questions tiene propiedades QuestionID y QuestionAnswer. Al iterar a través de este List of Question en foreach, tengo que encontrar .QuestionID = 12. Si encuentro .QuestionID = 12 entonces tengo que asignar inmediatamente un valor a .QuestionAnswer = "SomeText" de .QuestionID = 14.Usando LINQ, ¿cómo puedo encontrar un objeto con un valor de propiedad dado de una lista?

No quiero volver a iterar dentro de .QuestionId = 12' to find .QuestionID = 14` de nuevo.

¿Hay alguna manera de que pueda ir directamente al .QuestionID = 14 usando LINQ ?.

Por ejemplo:

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

Para mayor claridad, creo que esta pregunta está pidiendo un mecanismo que evita escribir explícitamente otra 'bucle dentro foreach' la instrucción 'if', no eliminando completamente el ciclo. Todas las respuestas dadas que involucran 'Any()' y 'FirstOrDefault()' efectivamente ocultan este segundo 'foreach' dentro de su respectiva implementación. –

Respuesta

17

Creo que usted está buscando algo como esto. Si tengo un momento, lo traduciré a VB, pero creo que puedes seguirlo.

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

Por favor, no anime a las personas traduciendo un código perfectamente bueno a VB. :) –

+6

ROFL. I * hate * VB – 5arx

+3

Podría ser peor, me quedé mirando una aplicación VB.net recientemente codificada que estaba escrita en un idioma VB6.

1

Por desgracia, la estructura de datos (List) exige que se busca de nuevo para encontrar Question-14 vez Question-12 se encuentra. Si su lista Question está ordenada por ID, entonces se pueden realizar algunas mejoras, pero en general, no hay forma de acceder directamente a un elemento de List o Array conociendo únicamente los valores de la propiedad del elemento.

La estructura de datos que se aplica a su problema es Dictionary, ya que permite la indexación de objetos a través de algún valor, así como el acceso directo eficiente a esos objetos sin la necesidad de recorrer la colección completa.

Puede encubiertas su lista a un diccionario utilizando LINQ llamando al método ToDictionary() extensión:

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

Este utiliza el ID del objeto Question como la clave, y el objeto como el valor. Luego, en su código, puede hacer lo siguiente:

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

Tenga en cuenta que ContainsKey y el indexador (operador []) tanto ejecutar en tiempo constante.

+0

¡Buena solución! Tenga en cuenta que debe asegurarse de que esa ID sea única en este caso o.ToDictionary() fallará. –

0

Eso sí, mi opinión es un poco más prolija que las otras muestras, pero logré hacerlo solo con LINQ. (Cuidado con los comentarios de tipo C por debajo!)

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 
0

mediante 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"; 
} 
Cuestiones relacionadas