Aggregation. Linq to objects query - c#

I have 3 classes
public class Test
{
private List<Question> _questions;
private string _text;
public string Text
{
get
{
return _text;
}
}
//...
}
public class Question
{
private List<Answer> _answers;
private string _text;
public string Text
{
get
{
return _text;
}
}
//...
}
public class Answer
{
private string _text;
private bool _isCorrect;
public string Text
{
get
{
return _text;
}
}
public bool isCorrect
{
get
{
return _isCorrect;
}
}
//...
}
I need to select a Text from Questions and Text from Answers, where Answer is correct.
I can only select correct Answers.
Test t;
//Initializing t
var r = t.SelectMany<Question, Answer>(q => q).Where<Answer>(a => a.isCorrect == true);
My question is:
How to select a Text from Questions and Text from Answers, where Answer is correct.
I need to make a linq to objects query.

Assuming Test implements IEnumerable<Question> and Question implements IEnumerable<Answers>:
var questionsWithCorrectAnswers = myTest
.SelectMany(q => q.Where(a => a.IsCorrect)
.Select(a => new { Question = q, Answer = a }));

First off, your Questions and Answers are private. I'll assume you have a public accessor Questions and Answers, respectively.
Try this:
var results = from q in t.Questions
where q.Answers.Any(a=>a.isCorrect)
select new {Question = q, CorrectAnswers = q.Answers.Where(a=>a.isCorrect)};
You can now reference results.Question and results.CorrectAnswers. You can also select a new Question where the Answers list contains only correct Answers.

Related

Using Linq to determine if there is more than 2 distinct items in a class

I have a class that contains a list of another class which has a property that I want to check if it has more than one distinct value.
e.g
public class BasketModel
{
public BasketModel()
{
BasketOrderLines = new List<BasketOrderLine>();
}
.
.
.
public class BasketOrderLine
{
public int OrderLineId { get; set; }
public string ImageUrl { get; set; }
public string ProductType { get; set; }
.
.
Given a basket model object I want to find out if there are more than one distinct value in the ProductType.
e.g If all Product Types are "A" then that would be false, if 3 products are of type "A" and one is of type "B" then this would be true.
Cheers
Macca
Your title: "more than two distinct", your question body: "more than one distinct"
If the title is a typo:
bool notDistinctTypes = theBasket.BasketOrderLine
.Select(o => o.ProductType)
.Distinct()
.Skip(1)
.Any();
This doesn't need to enumerate all items to find out if there is more than one ProductType.
// Does this basket contains three or more types
public bool HasSeveralTypes(BasketModel basket)
{
if (basket == null)
return false;
int differentTypes = basket.BasketOrderLines
.Select(l => l.ProductType)
.Distinct()
.Count();
return (differentTypes > 2);
}
Something like this :
Public bool CheckDistinct (){
var res = basketOrderLines.Select(o => o.ProductType).Distinct ().Count ();
return res > 1;
}
There are a few ways to do this, here's one:
public class BasketModel
{
public BasketModel()
{
BasketOrderLines = new List<BasketOrderLine>();
}
public bool HasMulitpleDistinctProducts
{
get
{
if (!BasketOrderLines.Any())
{
return true; // or false?
}
return BasketOrderLines.Select(b => b.ProductType).Distinct().Count() > 1;
}
}
}
Here is a type extension you can call directly from your list. The pros of this code is to be adaptable to any type implementing IEquals and not only string + kick to use from your code.
The code :
public static class Tools
{
public static bool fDistinctProductType(this List<BasketOrderLine> lstToAnalyse)
{
BasketOrderLine ProductTypeA = lstToAnalyse.FirstOrDefault();
if (ProductTypeA == null) // It's null when lstToAnalyse is empty
return false;
BasketOrderLine ProductTypeB = lstToAnalyse.Where(b => b.ProductType.Equals(ProductTypeA.ProductType)).FirstOrDefault();
if (ProductTypeB == null) // It's null when it doesn't exists a distinct ProductType
return false;
return true;
}
}
How to call:
List<BasketOrderLine> lst = new List<BasketOrderLine>();
// Add element to list
if (lst.fDistinctProductType())
{
// DO Something
}

Select specific record in CollectionVIewSource using code

Hie. I have what should be a simple question that's clearly above me. How to you get a collectionViewSource to select a specific record?
I've tried this:
private object Select_CommandExecute(object param)
{
// Select * From Signups where Tag = '2';
var select = context.signups.Where(s => s.tag == 2);
return signupsViewSource.View.MoveCurrentTo(select);
}
But all it does is clear all fields. Any idea how I do this?
no matter what number I pass in, the result is always the same.
I think Filter is what you are looking for. Here is a sample code using Filter.
IList<Employer> employers;
ICollectionView _employerView;
private string _filterString=string.Empty;
public Window1()
{
InitializeComponent();
employers = GetCustomers();
_employerView = CollectionViewSource.GetDefaultView(employers);
_employerView.Filter = EmployerFilter;
}
public bool EmployerFilter(object item)
{
Employer employer = item as Employer;
return employer.Name.ToLower().StartsWith(_filterString.ToLower());
}
public string FilterString
{
get { return _filterString; }
set{
_filterString = value;
OnPropertyChanged("FilterString");
_employerView.Refresh();
}
}
Hope this help.

C# how to avoid multiple foreach and if statements [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I have the below function that works and cycles through 3 possible levels.
Is there a way to do the same as the function below but not have to do the multiple foreach statements?
Basically the reponses list can contain multiple GroupResponseTypes
each of these can contain multiple ElementResponseBaseTypes
which can be a variety of types themselves
I'm interested in finding a value in an ElementResponseType
And each ElementResponseBaseType itself can be a GroupResponseType, it to containing multiple types.
So i'm looking at an easy way to scan through the whole structure for a specific Element.Reference
and return the relevant value
Any help is much appreciated
public static string GetValueFromFormField(List<ResponseBaseType> responses, string fieldref)
{
string fieldvalue = String.Empty;
foreach (GroupResponseType groups in responses)
{
foreach (ElementResponseBaseType firstelements in groups.Responses)
{
if (firstelements.GetType() == typeof(ElementResponseType))
{
if (firstelements.Element.Reference == fieldref)
{
ElementResponseType firstelement = new ElementResponseType();
firstelement = (ElementResponseType)firstelements;
fieldvalue = firstelement.Value;
}
}
else if (firstelements.GetType() == typeof(GroupResponseType))
{
GroupResponseType secondgroup = new GroupResponseType();
secondgroup = (GroupResponseType)firstelements;
foreach (ElementResponseBaseType secondelements in secondgroup.Responses)
{
if (secondelements.GetType() == typeof(ElementResponseType))
{
if (secondelements.Element.Reference == fieldref)
{
ElementResponseType secondelement = new ElementResponseType();
secondelement = (ElementResponseType)secondelements;
fieldvalue = secondelement.Value;
}
}
else if (secondelements.GetType() == typeof(GroupResponseType))
{
GroupResponseType thirdgroup = new GroupResponseType();
thirdgroup = (GroupResponseType)secondelements;
foreach (ElementResponseBaseType thirdelements in thirdgroup.Responses)
{
if (thirdelements.GetType() == typeof(ElementResponseType))
{
if (thirdelements.Element.Reference == fieldref)
{
ElementResponseType thirdelement = new ElementResponseType();
thirdelement = (ElementResponseType)thirdelements;
fieldvalue = thirdelement.Value;
}
}
}
}
}
}
}
}
return fieldvalue;
}
You need to identify which parts of your code are used repeatedly and factor them out into new methods. If you do that over and over, eventually you will obtain something like this:
public static string GetValueFromResponses(IEnumerable<ElementResponseBaseType> responses, string fieldref)
{
foreach (ElementResponseBaseType response in responses)
{
ElementResponseType element = response as ElementResponseType;
if (element != null)
{
string foundValue = CheckElement(element, fieldref);
if (foundValue != null)
{
return foundValue;
}
}
else
{
GroupResponseType group = response as GroupResponseType;
if (group != null)
{
string foundValue = GetValueFromResponses(group.Responses, fieldref);
if (foundValue != null)
{
return foundValue;
}
}
}
}
return string.Empty;
}
private static string CheckElement(ElementResponseType element, string fieldref)
{
if (element.Element.Reference == fieldref)
{
return element.Value;
}
return null;
}
Here's a version that uses Linq (this contains all of the functionality in your original method):
public static string GetValueFromResponses(IEnumerable<ElementResponseBaseType> responses, string fieldref)
{
var foundInElements = responses.OfType<ElementResponseType>()
.Select(e => CheckElement(e, fieldref));
var foundInGroups = responses.OfType<GroupResponseType>()
.Select(g => GetValueFromResponses(g.Responses,
fieldref));
return foundInElements.Concat(foundInGroups)
.FirstOrDefault(s => s != null) ?? string.Empty;
}
private static string CheckElement(ElementResponseType element, string fieldref)
{
if (element.Element.Reference == fieldref)
{
return element.Value;
}
return null;
}
You should give your base type, in this case ResponseBaseType, a member that returns all of it's decedent leaf nodes. You can then implement the behavior of that member separately for each type. The group type can return all of the leaves in all of its own children (recursively), and the single item can return itself.
You can then take any instance of the base type and get all of the leaves, or, in this case, the first leaf. Note that since you're only trying to get the first result here, not all of them, you'd benefit from making your implementation of the group's member use deferred execution, so that you don't need to bother computing all of the values just to get the first.
As complex as that might seem at first, it takes very little code to actually implement.
public abstract class ResponseBaseType
{
public abstract IEnumerable<ElementResponseType> Leaves { get; }
}
public class GroupResponseType : ResponseBaseType
{
public IEnumerable<ResponseBaseType> Children { get; private set; }
public override IEnumerable<ElementResponseType> Leaves
{
get
{
return Children.SelectMany(child => child.Leaves);
}
}
}
public class ElementResponseType : ResponseBaseType
{
public override IEnumerable<ElementResponseType> Leaves
{
get
{
yield return this;
}
}
}
This enables you to take your list of responses, map it to a sequences of all of their leaves, and then get the first/last leaf from that.
responses.SelectMany(response => response.Leaves).Last();

How can I convert data held as 01010 bits into fields in a class object?

I have two variables that contain true/false data. THe first variable can be null but the second variable is always non null. Both variables will always be the same length.
var AnswerGridCorrect = "000111"; // or null
var AnswerGridResponses = "000011";
How could I change this data into an object oriented form. I already created classes and these are below. Here's is what I need the output to look like when converted to JSON:
"answers":[ // Json conversion made Answers into answers
{"correct":null,"response":true},
{"correct":null,"response":true},
{"correct":null,"response":true},
{"correct":null,"response":false}
}
Note that I am using LINQ to output the data so I think what I need is a function with parameters something like this:
.Select((t, index) => new {
Answer = t.Answer,
Answers = makeAnswer(t.AnswerGridCorrect,
t.AnswerGridResponses)
});
I am not sure if this helps but here were the classes I was using when I did this from JSON:
public class AnswerRow
{
public bool? Correct { get; set; }
public bool Response { get; set; }
}
public class AnswerRowList
{
public IList<AnswerRow> AnswerRows { get; set; }
}
Here is an implementation for your makeAnswers method:
public List<AnswerRow> makeAnswers(string c, string r)
{
var result = new List<AnswerRow>();
for(var i=0; i<r.Length; i++)
{
result.Add(
new AnswerRow {
Correct = c!=null?new Nullable<bool>(c[i]=='1'):null,
Response = r[i]=='1'
});
}
return result;
}
Rene's answer is probably correct, but here's the (unnecessarily complex) Linq way:
AnswerRowList MakeAnswer(string answerGridCorrect, string answerGridResponses)
{
return new AnswerRowList()
{
AnswerRows = answerGridResponses.Zip(
answerGridCorrect == null ?
Enumerable.Repeat<bool?>(null, answerGridResponses.Length) :
answerGridCorrect.Select(x => new Nullable<bool>(x == '1')),
(r, c) => new AnswerRow()
{
Correct = c,
Response = r == '1'
}).ToList()
};
}

IEnumerable - Move Next

I have an IEnumerable from which I need to fetch each item and display it one by one. The displaying is not a continuous process..i.e I should fetch one item and display it on the UI, then wait for some user feedback on that item, and then move on to the next item. For example from the below code, I need to fetch a question, then display it to the user, then user hits enter, and then I move on to fetching the next question.
My Question is how do I do that? Is IEnumerable the best way of achieving this or should I revert to list and start storing the indexes and increment it one by one?
Please note that I'm using .NET 3.5.
Code:
class Program
{
static void Main(string[] args)
{
Exam exam1 = new Exam()
{
Questions = new List<Question>
{
new Question("question1"),
new Question("question2"),
new Question("question3")
}
};
var wizardStepService = new WizardStepService(exam1);
var question = wizardStepService.GetNextQuestion();
//Should output question1
Console.WriteLine(question.Content);
Console.ReadLine();
//Should output question2 but outputs question1
question = wizardStepService.GetNextQuestion();
Console.WriteLine(question.Content);
Console.ReadLine();
//Should output question3 but outputs question1
question = wizardStepService.GetNextQuestion();
Console.WriteLine(question.Content);
Console.ReadLine();
}
}
public class Question
{
private readonly string _text;
public Question(string text)
{
_text = text;
}
public string Content { get { return _text; } }
}
internal class Exam
{
public IEnumerable<Question> Questions { get; set; }
}
internal class WizardStepService
{
private readonly Exam _exam;
public WizardStepService(Exam exam)
{
_exam = exam;
}
public Question GetNextQuestion()
{
foreach (var question in _exam.Questions)
{
//This always returns the first item.How do I navigate to next
//item when GetNextQuestion is called the second time?
return question;
}
//should have a return type hence this or else not required.
return null;
}
}
Yes, GetEnumerator() should work fine; although strictly speaking you need to handle Dispose():
internal class WizardStepService : IDisposable
{
private IEnumerator<Question> _questions;
public WizardStepService(Exam exam)
{
_questions = exam.Questions.GetEnumerator();
}
public void Dispose()
{
if (_questions != null) _questions.Dispose();
}
public Question GetNextQuestion()
{
if (_questions != null)
{
if (_questions.MoveNext())
{
return _questions.Current;
}
Dispose(); // no more questions!
}
//should have a return type hence this or else not required.
return null;
}
}
and also:
using (var wizardStepService = new WizardStepService(exam1))
{
var question = wizardStepService.GetNextQuestion();
//Should output question1
Console.WriteLine(question.Content);
Console.ReadLine();
//Should output question2 but outputs question1
question = wizardStepService.GetNextQuestion();
Console.WriteLine(question.Content);
Console.ReadLine();
//Should output question3 but outputs question1
question = wizardStepService.GetNextQuestion();
Console.WriteLine(question.Content);
Console.ReadLine();
}
However, since you're not actually testing the result each time, you could also do something like:
using (var questions = exam1.Questions.GetEnumerator())
{
questions.MoveNext();
var question = questions.Current;
//Should output question1
Console.WriteLine(question.Content);
Console.ReadLine();
//Should output question2 but outputs question1
questions.MoveNext();
question = questions.Current;
Console.WriteLine(question.Content);
Console.ReadLine();
//Should output question3 but outputs question1
questions.MoveNext();
question = questions.Current;
Console.WriteLine(question.Content);
Console.ReadLine();
}
Or as a final thought, perhaps just:
var questions = exam1.Questions.Take(3).ToArray();
//Should output question1
Console.WriteLine(questions[0].Content);
Console.ReadLine();
//Should output question2 but outputs question1
Console.WriteLine(questions[1].Content);
Console.ReadLine();
//Should output question3 but outputs question1
Console.WriteLine(questions[2].Content);
Console.ReadLine();
Well you could store an IEnumerator<T> instead, and change GetNextQuestion to:
return _exam.MoveNext() ? _exam.Current : null;
However, at that point you're not actually adding any value with the Exam or WizardStepService classes, and you might as well just use IEnumerator<T> directly in Main. Note that your Main method itself is a little odd - it has repeated code where a foreach loop would be simpler - and you're unconditionally asking three questions.
Note that if you have a type with an IEnumerator<T> as a field, you probably want to implement IDisposable in order to dispose of the iterator, too - it all gets a bit messy.
Try this:
class Program2
{
static void Main(string[] args)
{
Exam exam1 = new Exam()
{
Questions = new List<Question>
{
new Question("question1"),
new Question("question2"),
new Question("question3")
}
};
var wizardStepService = new WizardStepService(exam1);
foreach (var question in wizardStepService.GetQuestions())
{
Console.WriteLine(question.Content);
Console.ReadLine();
}
}
}
public class Question
{
private readonly string _text;
public Question(string text)
{
_text = text;
}
public string Content
{
get
{
return _text;
}
}
}
internal class Exam
{
public IEnumerable<Question> Questions
{
get;
set;
}
}
internal class WizardStepService
{
private readonly Exam _exam;
public WizardStepService(Exam exam)
{
_exam = exam;
}
public IEnumerable<Question> GetQuestions()
{
foreach (var question in _exam.Questions)
{
//This always returns the first item.How do I navigate to next
//item when GetNextQuestion is called the second time?
yield return question;
}
//should have a return type hence this or else not required.
//return null;
}
}

Categories