How to convert float to system.Collection.generic.IEnumerable - c#

How to convert float to system.Collection.generic.IEnumerable
The actual problem occurs when I try to iterate through the returned IEnumerable.
Code
private ObservableRangeCollection<ReviewInfo> _rating = new ObservableRangeCollection<ReviewInfo>();
public ObservableRangeCollection<ReviewInfo> Review
{
get { return _rating; }
set { _rating = value; OnPropertyChanged("AvRating"); }
}
public async Task GetReview()
{
var ber_id= berProfile.Id;
ResponseInfo<ReviewInfo> res = await nsManager.Instance.GetReview(ber_id);
Device.BeginInvokeOnMainThread(async () => {
IsBusy = false;
if (res.IsError == true)
{
await _page.Alert(res.Message);
}
else
{
if (res.Data != null && res.Data.Count > 0)
{
var temp = res.Data.Average(x => x.Rating);
Review.AddRange(temp);
}
}
});
}

Review is a collection of GogroomCustomer.Models.ReviewInfo, so you should create ReviewInfo object from temp by constructor or set via Property (ex: reviewInfo), then use Add or AddRange method:
Review.Add(reviewInfo);
or
Review.AddRange(new ReviewInfo[] { reviewInfo });

Your question is quite unclear as you didn´t provide what a ReviewInfo is. However your error is quite clear: you´re trying to add a float to a list of ReviewInfo. Of course this won´t work.
From your code I suppose this class has at least a Rating-property or field. Assuming you have a list of those ReviewInfo-instances you probably want to retrieve that object whose Rating-property is the average of all the elements within your list.
If this is the case your solution is simply this:
var temp = res.Data.Average(x => x.Rating);
Review.Add(res.Data.First(x.Rating == tmp));
However as Average returns a double it is fairly possible that there´s no element with exactly this rating in your list, so it´s better to apply some tolerance. However this goes too far on guessing what you actually want.

Related

Unit Testing: Can't figure this out?

I'm doing a unit test in my design class, and the shell of the project was given to us. There is only one method in the unit test where I have to add code. I can't change anything else in the code.
I have tried everything I could think of using what C++ knowledge I have and tried Googling different ways to solve this problem. Every result that came up was either too complex because I don't have a background with C#, or the information for what I was looking for was not given.
Here is the original code:
class Course
{
public Course(string id, string title, int creditHours, string description, string prerequisiteCourse)
{
this.CourseID = id;
this.CourseTitle = title;
this.CreditHours = creditHours;
this.Description = description;
this.PrerequisiteCourse = prerequisiteCourse;
}
public string CourseID;
public string CourseTitle;
public int CreditHours;
public string Description;
public string PrerequisiteCourse;
}
class CourseListTest
{
public static void Main(string[] args)
{
GetCourseByCourseIDTestWhenCourseExists();
GetCourseByCourseIDTestWhenCourseDoesNotExist();
}
public static void GetCourseByCourseIDTestWhenCourseExists()
{
CourseList myCourseList = new CourseList();
Course myCourse = myCourseList.GetCourseByCourseID("CIS 400");
if (myCourse.CourseID != "CIS 400")
System.Console.WriteLine("ERROR - GetCourseByCourseIDTestWhenCourseExists(): Returned CourseID Not equal (CIS 400)");
}
public static void GetCourseByCourseIDTestWhenCourseDoesNotExist()
{
CourseList myCourseList = new CourseList();
Course myCourse = myCourseList.GetCourseByCourseID("CIS 101");
if (myCourse != null)
System.Console.WriteLine("ERROR - GetCourseByCourseIDTestWhenCourseDoesNotExist(): should have returned null");
}
}
Here is were the problem lies in the next class. We are to enter code into the GetCourseByCourseID method which is where I get stuck.
class CourseList
{
public Course[] CourseArray =
{
new Course ("CIS 400", "OO Analysis & Design", 4, "Important class", "CIS 110") ,
new Course ("CIS 150A" , "VB.NET Programming", 4, "Good Introduction to programming", "CIS 100") ,
new Course ("CIS 150B", "C# Programming with labs", 4, "Follow-up to CIS 100", "CIS 100")
};
public Course GetCourseByCourseID(string id)
{
}
}
Since "CIS 101" is not a course in the CourseList we have to return null. The whole point of the exercise is to get the console to display nothing. That means the code is working properly.
I don't want the answer. I was just wanted an example of how to get this to work. Being that the code was already given to us.
i'll keep this close to c++ syntax.
there are many other ways but...
public Course GetCourseByCourseID(string id)
{
for(int x = 0; x < CourseArray.Length; x++)
{
if(CourseArray[x].CourseID == id) {return CourseArray[x];}
}
return null;
}
your array is static you could just use x < 3
and for a more c# way
using System.Linq;
public Course GetCourseByCourseID(string id)
{
return CourseArray.Where(a => a.CourseID == id).FirstOrDefault();
}
a is each course and First return the first element in the resulting collection. a pit fall with this approach is that if you have more than one Course with the same id you only get the first one.
but then that is likely a design flaw.
it should be noted that if CourseArray were to be multidimensional. then length would not be usable because it return the total number of elements in all dimensions of the array. thus using System.Linq Count() extension method would have to be used.
The simplest way would be to use a foreach loop, checking through all the courses until the ID matches. If no ID matches, the loop will exit and you should return null.
The more 'advanced' way would be to use LINQ, either straight up LINQ or the extension methods to achieve the same result but with less code.
With any language it is best to state a return variable which will start in a failure state. Then do the work of trying to find the non failure state and assign it to the return variable. If one doesn't find a non failure state, no assignment is done and the return value is correct as null.
Example:
public Course GetCourseByCourseID(string id)
{
Course foundCourse = null;
if (CourseArray != null)
{
// Check course array here for the id and if one is found, assign to foundCourse.
}
return foundCourse;
}
So within the if's you can continue to remove any possible failure situations. The one above in the if checks CourseArray for null. If it is null it gracefully exits and doesn't throw an exception about trying to check CourseArray. Keep doing 'sanity' checks where possible and it makes for better programming.

How to change values while looping through an IEnumerable

I keep getting stuck on this issue and have done a lot of searching/reading to try to understand the problem, but I just don't get it. Am wondering if someone can provide me with an example of how to update object values while looping an IEnumerable<>.
Example:
public class MyClass
{
private IEnumerable<MyData> _MyData = null;
public MyClass() {}
public MyClass(string parm1, int parm2) { Load(parm1, parm2); }
public IEnumerable<MyData> Load(string parm1, int parm2)
{
_MyData = _dbContext.MyData.Where(m => m.Parm1 == parm1 && m.Parm2 == parm2);
foreach(MyData mydata in _MyData)
{
if(mydata.Parm2 == 1)
{
mydata.Parm1 = "Some value";
}
}
return _MyData;
}
}
The above code doesn't work as any changes made to mydata.Parm1 within the loop are not retained. I read an SO article that suggested to make changes like this:
for (int i = 0; i < _MyData.Count(); i++)
{
_MyData.Skip(i).FirstOrDefault().Parm1 = "Some Value";
}
This works, but it's really ugly and hard for me to believe there isn't a cleaner way. For a single change it might be acceptable, but I have several changes that need to be made. So I've attempted this:
for (int i = 0; i < _MyData.Count(); i++)
{
MyData md = _MyData.ElementAt(i);
md.Parm1 = "Some Value";
}
But I don't understand how to put the modified md back into _MyData to save changes.
I think the main reason I'm going through all of these hoops is that I don't understand how to make changes to the elements and have them retained. Any changes I make seem to revert back to their original values unless I go through these hoops. Maybe someone can point out where I'm going wrong. I would like to use this class like this:
IEnumerable<MyData> MyDataResult = new MyClass("Parm1", 4);
Using the above line of code, I can trace through the Load() function and see that the desired changes are being made, but once finished MyDataResult contains the original values instead of those I saw being changed.
It is more then obvious that my code is wrong, but I hope I've been clear enough to illustrate what I'm wanting to do and where I'm having difficulty.
Try this -
_MyData = _dbContext.MyData.Where(m => m.Parm1 == parm1 && m.Parm2 == parm2).ToList();
To be clear, essentially what you have in your current code is a query, which you are enumerating in your Load method, trying to update some of its properties, but then in the end, you end up returning the query, and not the updated values in the query.
The caller of Load method, will end up running the query a second time, only to see direct values from the database.
Adding .ToList to the end of the query in Load method, materializes the query, and then you are doing rest of the operations in memory.
EDIT:
Just in case, if there would be performance concern over the large amount of data this query may return, then you could also consider this alternate approach -
public IEnumerable<MyData> Load(string parm1, int parm2)
{
_MyData = _dbContext.MyData.Where(m => m.Parm1 == parm1 && m.Parm2 == parm2);
foreach(MyData mydata in _MyData)
{
if(mydata.Parm2 == 1)
{
mydata.Parm1 = "Some value";
}
yield return myData;
}
}
This would keep the query lazy, and still return the modified values, as caller of Load iterates over the IEnumerable<MyData> returned by Load.
Not sure why you are returning a value which never gets used. You just need to set _MyData in your Load method as it is a class level variable.
Change Load to not return a value and ToList() your query on the db context and then set your _MyData to your concrete list object in Load.
Something like this will work - I've simplified your example slightly but same principals:
public class MyClass
{
public IEnumerable<string> _MyData = null;
public IEnumerable<string> _dbContext = new List<string> {"a", "b", "aa", "bb"};
public MyClass(){}
public MyClass(string parm1, int parm2){Load(parm1, parm2);}
public void Load(string parm1, int parm2)
{
var somedata = _dbContext.Where(m => m.Length == 2).ToList();
var myData = somedata.Select(s => s == parm1 ? "something else" : s).ToList();
_MyData = myData;
}
}
Use can use
var a = new MyClass("aa",1)._MyData;
and "aa" will get replaced with "something else" and be returned to "a".
You can't use a class like this:
IEnumerable<MyData> MyDataResult = new MyClass("Parm1", 4);
If you ask for an MyClass you'll get a MyClass not an IEnumerable.
If your call to dbContext is to an underlying data source you may be better off not doing that in the class constructor and always call Load explicitly following class construction. You then have options to avoid thread blocking on a potentially long running I/O operation.

Updating the original reference to an object that was returned from a linq query

I would like to do something like this:
[HttpPost]
public JsonResult Submit(Person UpdatedPerson)
{
//Find the original Person that the model was bound against
//Update the collection's reference to reflect the changes
//from the posted model version
Person original = PersonCollection
.SingleOrDefault(p=>p.Id == UpdatedPerson.Id);
if(original!=null)
{
//update the value from PersonCollection
//doesn't work, of course
original = UpdatedPerson;
}
}
I'm currently doing this:
[HttpPost]
public JsonResult Submit(Person UpdatedPerson)
{
//Find the index into PersonCollection for the original
//model bound object, use the index to directly mutate the
//PersonCollection collection
int refIndex = -1;
for(int i=0;i<PersonCollection.Length;i++)
{
if(PersonCollection[i].Id == UpdatedPerson.Id)
{
refIndex = i;
break;
}
}
if(refIndex >= 0)
{
PersonCollection[refIndex] = UpdatedPerson;
}
}
It feels like I'm missing something simple here, it shouldn't be so much trouble to accomplish what I'm after.
What is the best practice way to do this sort of stuff?
When you do this:
original = UpdatedPerson;
you are just assigning the reference to original, thus original now points to the same object that UpdatedPerson points to. and that is why you are losing the reference value for the object that you have retrieved from the collection.
Try assigning the individual fields instead.
In your first example, you make a variable declaration:
Person original;
That original variable is a reference.
Then you assign it to some item in your list
Then later you make a call like this:
original = UpdatedPerson;
In this call, you're updating the variable reference, not anything from the collection.
What you might want to do is something like this (Presuming Person is a class, not a struct):
original.UpdateValuesToMatch(UpdatedPerson);
but you'd have to create such a method on the person object.
Or in your second method, you could simplify from:
if(PersonCollection[i].Id == UpdatedPerson.Id)
{
refIndex = i;
break;
}
}
if(refIndex >= 0)
{
PersonCollection[refIndex] = UpdatedPerson;
}
to
if(PersonCollection[i].Id == UpdatedPerson.Id)
{
PersonCollection[i] = UpdatedPerson;
break;
}
}
Description
You can use FindIndex
Sample
[HttpPost]
public JsonResult Submit(Person UpdatedPerson)
{
//Find the index into PersonCollection for the original
//model bound object, use the index to directly mutate the
//PersonCollection collection
int refIndex = PersonCollection.FindIndex(x => x.Id == UpdatedPerson.Id);
if (refIndex != -1)
PersonCollection[refIndex] = UpdatedPerson;
}
More Information
List.FindIndex Method

Does LINQ to objects stop processing Any() when condition is true?

Consider the following:
bool invalidChildren = this.Children.Any(c => !c.IsValid());
This class has a collection of child objects that have an IsValid() method. Suppose that the IsValid() method is a processor intensive task. After encountering the first child object where IsValid() is false, theoretically processing can stop because the result can never become true. Does LINQ to objects actually stop evaluating after the first IsValid() = false (like a logical AND) or does it continue evaluating all child objects?
Obviously I could just put this in a foreach loop and break on the first invalid result, but I was just wondering if LINQ to objects is smart enough to do this as well.
EDIT:
Thanks for the answers, for some reason I didn't think to look it up on MSDN myself.
Yes it does. As soon as it finds a match, the criteria is satified. All is similar in that it checks all items but if one doesn't match it ends immeditately as well.
Exists works in the same manner too.
Any
The enumeration of source is stopped as soon as the result can be determined.
Exists
The elements of the current List are individually passed to the Predicate delegate, and processing is stopped when a match is found.
All
The enumeration of source is stopped as soon as the result can be determined.
etc...
Yes, it stops as soon as the results can be evaluated. Here's a quick proof:
class Program
{
static void Main(string[] args)
{
bool allvalid = TestClasses().Any(t => !t.IsValid());
Console.ReadLine();
}
public static IEnumerable<TestClass> TestClasses()
{
yield return new TestClass() { IsValid = () => { Console.Write(string.Format("TRUE{0}",Environment.NewLine)); return true; } };
yield return new TestClass() { IsValid = () => { Console.Write(string.Format("FALSE{0}", Environment.NewLine)); return false; } };
yield return new TestClass() { IsValid = () => { Console.Write(string.Format("TRUE{0}", Environment.NewLine)); return true; } };
yield return new TestClass() { IsValid = () => { Console.Write(string.Format("TRUE{0}", Environment.NewLine)); return true; } };
}
}
public class TestClass
{
public Func<bool> IsValid {get;set;}
}
Yes it will stop after it encounters the first item for which the condition matches, in your case the first item for which c.IsValid() returns false.
From MSDN:
The enumeration of source is stopped
as soon as the result can be
determined.
Here's a quick and dirty empirical test to see for yourself:
class Kebab
{
public static int NumberOfCallsToIsValid = 0;
public bool IsValid()
{
NumberOfCallsToIsValid++;
return false;
}
}
...
var kebabs = new Kebab[] { new Kebab(), new Kebab() };
kebabs.Any(kebab => !kebab.IsValid());
Debug.Assert(Kebab.NumberOfCallsToIsValid == 1);
The result is that yes, the Any LINQ operator stops as soon as a collection item matches the predicate.
as per MSDN,
The enumeration of source is stopped as soon as the result can be determined.

Code structure, a methods should only do one thing

I am having a bit following the "a method should only do one thing"
I have a car text file, and if it contains even one BMW I want to set isValid to true, but while I am going through the text file anyways I thought I would also populate two list high end models(M3,M5 etc) and lower model (335, X3 etc).
I know that method should only do one thing, but it seems so convenient for it to also populate the lists. Here is what I have:
private bool hasBMWegments()
{
foreach (ClassLib.CarSegment carElement in CarSegmentFactory.ContainsCar("BMW"))
{
isValid = true;
if (carElement.Class.IndexOfAny(lowerModels) == 0)
{
lstOlderSegment.Add(carElement.ElementNumber);
}
if (carElementClass.IndexOfAny(upperModels) == 0)
{
lstNewerSegment.Add(carElement.ElementNumber);
}
}
return isValid;
}
Should I just create a method that performs the foreach check again? Or should I create another method inside that method (I would think that would be messy, and wouldn't related to the method name)
edit: sorry working with framework 2.0
I find that code to be a mess compared to this:
private IEnumerable<ClassLib.CarSegment>
GetModels(IEnumerable<ClassLib.CarSegment> segments, string modelID)
{
return segments.Where(x => x.Class.IndexOfAny(modelID) == 0);
}
// ...
var bmwSegments = CarSegmentFactory.ContainsCar("BMW").ToArray();
bool isValid = bmwSegments.Any();
var olderModelSegments = GetModels(bmwSegments, lowerModels);
var newerModelSegments = GetModels(bmwSegments, upperModels);
This code is obviously correct at a glance. The other code makes you look twice at the loop to figure out what's going on.
It looks like all you're doing is setting isValid to true on the first pass through the foreach. So all isValid really means is "is there at least one element?".
In which case you do not need to iterate twice. You can use Any() to do the valid check:
bool IsValid(IEnumerable<CarSegment> elements)
{
return elements.Any();
}
void PopulateSegments(IEnumerable<CarSegment> elements)
{
foreach(var element in elements)
{
//add to lists
}
}

Categories

Resources