C# - Closing brackets aren't being recognized [duplicate] - c#

This question already has an answer here:
C# - Retrieve data from persistence storage and save it to the view model
(1 answer)
Closed 2 years ago.
I have a controller method that looks like this
public ActionResult SpecialOrderSummary(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
JobOrder jobOrder = db.JobOrders.Find(id);
if (jobOrder == null)
{
return HttpNotFound();
}
ViewBag.JobOrderID = jobOrder.ID;
ItemInstance ii = db.ItemInstances.Where(x => x.serialNumber == jobOrder.serialNumber).FirstOrDefault();
Item item = db.Items.Find(ii.ItemID);
var vm = new ItemViewModel
{
ItemId = item.ItemID,
ItemName = item.Name,
Parts = new List<ItemPartViewModel>
{
foreach (ItemHasParts ihp in item.IHP)
{
Part part = db.Parts.Find(ihp.PartID);
new ItemPartViewModel
{
PartId = part.ID,
PartName = part.Name
};
}
} //this is closing method
}; // this is closing controller
return View(vm);
}
But the closing } to the Parts list and the vm aren't closing the right brackets. Instead, the Parts } is closing the method while the vm } is closing the controller.
Why is this happening? Is there an issue with my syntax?

Yea you can't have a foreach loop inside the Parts list initialization.
You have to do:
var vm = new ItemViewModel
{
ItemId = item.ItemID,
ItemName = item.Name,
Parts = new List<ItemPartViewModel>()
};
foreach (ItemHasParts ihp in item.IHP)
{
Part part = db.Parts.Find(ihp.PartID);
vm.Parts.Add(new ItemPartViewModel
{
PartId = part.ID,
PartName = part.Name
};
}
I am surprised the compiler actually let you compile?

Not sure what you're aiming to do here:
Parts = new List<ItemPartViewModel>
{
foreach
If this is initializing the Parts variable it cannot contain a foreach loop
Collection initializers need to contain a fixed number of elements. You can use variables and expressions but you must have a definite number of them:
var stringList = new List<string>() { "a", "b", "c", "d"+"e", person.Name };
The compiler will turn this into a bunch of calls to Add()
If you have some variable number of items you could Add, AddRange or make a LINQ query to form your list:
foreach(var person in myPeople)
stringList.Add(person.Name);
//or
stringList.AddRange(myStringArray);
//or
stringList = people.Select(x => x.Name).ToList();
That last one isn't adding to an existing list; it's replacing the list wholesale with another list. If you wanted to add to an existing you could:
stringList.AddRange(people.Select(x => x.Name));
The result of the LINQ query being an enumerable list of strings

Related

Merge data from two arrays or something else

How to combine Id from the list I get from file /test.json and id from list ourOrders[i].id?
Or if there is another way?
private RegionModel FilterByOurOrders(RegionModel region, List<OurOrderModel> ourOrders, MarketSettings market, bool byOurOrders)
{
var result = new RegionModel
{
updatedTs = region.updatedTs,
orders = new List<OrderModel>(region.orders.Count)
};
var json = File.ReadAllText("/test.json");
var otherBotOrders = JsonSerializer.Deserialize<OrdersTimesModel>(json);
OtherBotOrders = new Dictionary<string, OrderTimesInfoModel>();
foreach (var otherBotOrder in otherBotOrders.OrdersTimesInfo)
{
//OtherBotOrders.Add(otherBotOrder.Id, otherBotOrder);
BotController.WriteLine($"{otherBotOrder.Id}"); //Output ID orders to the console works
}
foreach (var order in region.orders)
{
if (ConvertToDecimal(order.price) < 1 || !byOurOrders)
{
int i = 0;
var isOurOrder = false;
while (i < ourOrders.Count && !isOurOrder)
{
if (ourOrders[i].id.Equals(order.id, StringComparison.InvariantCultureIgnoreCase))
{
isOurOrder = true;
}
++i;
}
if (!isOurOrder)
{
result.orders.Add(order);
}
}
}
return result;
}
OrdersTimesModel Looks like that:
public class OrdersTimesModel
{
public List<OrderTimesInfoModel> OrdersTimesInfo { get; set; }
}
test.json:
{"OrdersTimesInfo":[{"Id":"1"},{"Id":"2"}]}
Added:
I'll try to clarify the question:
There are three lists with ID:
First (all orders): region.orders, as order.id
Second (our orders): ourOrders, as ourOrders[i].id in a while loop
Third (our orders 2): from the /test.json file, as an array {"Orders":[{"Id":"12345..."...},{"Id":"12345..." ...}...]}
There is a foreach in which there is a while, where the First (all orders) list and the Second (our orders) list are compared. If the id's match, then these are our orders: isOurOrder = true;
Accordingly, those orders that isOurOrder = false; will be added to the result: result.orders.Add(order)
I need:
So that if (ourOrders[i].id.Equals(order.id, StringComparison.InvariantCultureIgnoreCase)) would include more Id's from the Third (our orders 2) list.
Or any other way to do it?
You should be able to completely avoid writing loops if you use LINQ (there will be loops running in the background, but it's way easier to read)
You can access some documentation here: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/introduction-to-linq-queries
and you have some pretty cool extension methods for arrays: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable?view=net-6.0 (these are great to get your code easy to read)
Solution
unsing System.Linq;
private RegionModel FilterByOurOrders(RegionModel region, List<OurOrderModel> ourOrders, MarketSettings market, bool byOurOrders)
{
var result = new RegionModel
{
updatedTs = region.updatedTs,
orders = new List<OrderModel>(region.orders.Count)
};
var json = File.ReadAllText("/test.json");
var otherBotOrders = JsonSerializer.Deserialize<OrdersTimesModel>(json);
// This line should get you an array containing
// JUST the ids in the JSON file
var idsFromJsonFile = otherBotOrders.Select(x => x.Id);
// Here you'll get an array with the ids for your orders
var idsFromOurOrders = ourOrders.Select(x => x.id);
// Union will only take unique values,
// so you avoid repetition.
var mergedArrays = idsFromJsonFile.Union(idsFromOurOrders);
// Now we just need to query the region orders
// We'll get every element that has an id contained in the arrays we created earlier
var filteredRegionOrders = region.orders.Where(x => !mergedArrays.Contains(x.id));
result.orders.AddRange(filteredRegionOrders );
return result;
}
You can add conditions to any of those actions (like checking for order price or the boolean flag you get as a parameter), and of course you can do it without assigning so many variables, I did it that way just to make it easier to explain.

I try to make a lamda expression in C# for filtering a list and can't make it work when I compare a variable to an item in an array

So I have the gui set up so that I have two main listboxes. I'm still figuring out what kind of gui I want for this application so there is another one but that's not relevant. One listbox is a list of options for what you want to check for a department or an employee. The other is a list of departments. Right now I have the functionality for the name option to view the names of employees for a department. I just need to know how I can filter a list so that the only employees that show up are the ones who are in the chosen department after I click on the submit button. I figured I would use a lambda expression for that and it hasn't been working for me. I really want to know how to use lambda expressions better so please only give me a solution that involves using them. If it's impossible or if it would be more efficient to do something else then let me know.
File where I put reads and set dept array to file contents
//list of employees
public static List<Employee> EmployeeList = new List<Employee>();
//array to hold the options users have for interacting with info
public static string[] OptionsArr;
//array to hold the departments
public static string[] DeptsArr;
//skipping around same file to relevant code
//set the departments array to the contents of the depts file
DeptsArr = File.ReadAllLines("..\\..\\departments.txt");
Not sure if needed
Method for populating DeptListBox
private void UpdateDeptListBox()
{
//set up for new info
DeptListBox.Items.Clear();
//prevent interfence with update
DeptListBox.BeginUpdate();
//set department listbox to depts array
DeptListBox.DataSource = Program.DeptsArr;
DeptListBox.EndUpdate();
}
Problem Method - the submit button method
List<Employee> ResultList = new List<Employee>();
//name
if (OptionsListBox.SelectedIndex == 1)
{
//user selects Marketing department
if (DeptListBox.SelectedIndex == 0)
{
//problem is either with lambda exp or Program.DeptsArr comparison
foreach (Employee empl in Program.EmployeeList.Where(empl => empl.Dept.CompareTo(Program.DeptsArr[0]) == 0).ToList())
{
//this doesn't happen
ResultList.Add(empl);
}
for (int i = 0; i<ResultList.Count; i++)
{
ResultListBox.Items.Add(ResultList[i].Lname + " " + ResultList[i].Fname + " " + ResultList[i].Dept);
}
}
}
}
For me it can be helpful when I am having issues to break stuff down and look at smaller pieces. Are you sure the issue is your lambda function? It may be your options listbox != 1 or that the data is not being read in correctly.
As far as I can tell, this part should work. Although there are some issues with it:
foreach (Employee empl in Program.EmployeeList.Where(empl =>empl.Dept.CompareTo(Program.DeptsArr[0]) == 0).ToList())
{
//this doesn't happen
ResultList.Add(empl);
}
You could start with just the Employee lambda function and hard code the values. Maybe something like this which does indeed produce the correct results (Bob and Brandon)
List<Employee> ResultList = new List<Employee>();
List<Employee> EmployeeList = new List<Employee> {
new Employee{ Name = "Bob", Dept = "Accounting" },
new Employee{ Name = "Larry", Dept = "A" },
new Employee{ Name = "Margret", Dept = "B" },
new Employee{ Name = "Brandon", Dept = "Accounting" }
};
string[] DeptsArr = new string[2];
DeptsArr[0] = "Accounting";
DeptsArr[1] = "A";
//user selects Marketing department
if (departmentIndex == 0)
{
foreach (Employee empl in EmployeeList.Where(empl => empl.Dept.CompareTo(DeptsArr[0]) == 0).ToList())
{
ResultList.Add(empl);
}
}
However your lamda function inside a foreach loop is redundant. You can think of a lambda function as an instruction for running a foreach loop. A foreach loop by itself could look like this:
List<Employee> ResultList = new List<Employee>();
foreach (Employee empl in EmployeeList)
{
if(empl.Dept == DeptsArr[0])
{
ResultList.Add(empl);
}
}
You could get the same result as the foreach loop above, by using the following lamda function:
List<Employee> ResultList = EmployeeList.Where(empl => empl.Dept == DeptsArr[0]).ToList();
A final note is that the "ToList()" on the end of that lambda function is what executes the loop and returns the result as a List. Many times this is not required. Without the "ToList()" part an IEnumerable will be returned which you may be able to use instead. Using an IEnumerable instead of calling ToList() can have better performance in many scenarios.
If you want to test whether a specific value is in an array then you call Contains on that array, e.g.
var allEmployees = new List<Employee>();
// Populate allEmployees here.
var selectedEmployees = allEmployees.Where(e => selectedDepartments.Contains(e.Department)).ToArray();
The selectedEmployees array will contain only the Employee objects from the allEmployees list with a Department property value that is contained in the selectedDepartments array/collection.

Comparing attributes from a List inside a List

Description
My goal is to compare the language of a menu object from the menuList. Since the menuList has the Languages offered as another list it makes it a bit more complicated. So I tried to create a new class object with the same values so I can use menuList.Languages.Contains(languageObject), however I quickly found out that this doesn't work like that. I tried to make a for loop inside a for loop which didn't work either, but could be a failure from my side.
Obviously I can't write something like: MenuList.Languages.Name.Equals("English").
Because of that I am looking for a solution where I can check if the attribute Name of the Languages-List inside the menuList equals a value of my choice.
The Object
private LanguageBox LangEng = new LanguageBox
{
IsoCode = "eng",
Name = "English"
};
The List
var MenuList = menuDataClient.GetMenuByCity(city)
.Select(nap => new MenuBox()
{
Menu = nap.Menu,
Languages = nap.Languages
.Select(lang => new LanguageBox()
{
IsoCode = lang.IsoCode,
Name = lang.Name
}).ToList()
})
.ToList();
The Loop
for (int i = 0; i < MenuList.Count; i++)
{
if (MenuList[i].Languages.Contains(LangEng))
{
System.Console.WriteLine("Success");
}
}
Maybe linq's Where could do the trick? Sth like:
foreach(var item in MenuList)
{
var x = item.Languages.Where(obj => obj.Name == <desired language>);
if (x.Count() > 0)
{
//Success code
break;
}
}
I have found a solution. This LINQ option works if you want to only keep elements in the list which have English or Russian in their Languages-List.
Solution
.Where(lang => lang.Languages.Any(any => any.Name.Equals("English") || any.Name.Equals("Russian")))

Adding element to a list in class, which is a part of List<class>, based on condition

Let's have a simple class with 2 fields
public class Sample
{
public int IdOfSample;
public string SampleName;
}
And another using this one
public class ListOfSamples
{
public int IdOfList;
public List<Sample> SampleList;
}
And finally, since we will use a couple of different ListOfSamples, make a list of them:
public static List<ListOfSamples> FinalList = new List<ListOfSamples>();
Now the problem:
I create a new Sample (let's call it NewItem), with some name and Id. I want to check if there's a ListOfSamples in my FinalList that as the same Id as the NewItem I have. Otherwise create new ListOfSamples in the FinalList with the IdOfList = NewItem.IdOfSample.
I think I got the first part which checks if you should add a new list (ie. a ListOfSamples with specified IdOfList does not exist:
Sample NewItem = new Sample()
{
IdOfSample = 12345,
SampleName = "Some name"
};
int index = FinalList.FindIndex(f => f.IdOfList == NewItem.IdOfSample);
if (!FinalList.Any() || index == -1)
{
ListOfSamples NewList = new ListOfSamples()
{
IdOfList = NewItem.IdOfSample,
SampleList = new List<Sample>()
};
NewList.SampleList.Add(NewItem);
FinalList.Add(NewList);
}
Now, I'm trying to construct a statement, that, if the list with specified Id already exists in the FinalList, just add the new item to it, but so far I think my limited experience with LINQ is showing, nothing I try seems to work.
So:
If there exists a ListOfSamples with IdOfList == NewItem.IdOfSample in FinalList, then add NewItem to that ListOfSamples.
How about
if (!FinalList.Any() || index == -1)
...
else
{
FinalList[index].SampleList.Add(NewItem);
}
If you just wanted to check whether the list item existed, a suitable LINQ statement could be:
if (FinalList.Any(l => l.IdOfList == NewItem.IdOfSample))
{
// ...
}
Given you want to work on the item then you could attempt to retrieve it as follows:
var existingList = FinalList.SingleOrDefault(l => l.IdOfList == NewItem.IdOfSample);
if (existingList != null)
{
existingList.Add( ... );
}
Though perhaps it's worth thinking about using a HashSet of lists if you want to guarantee uniqueness...
if i understand it right ...
// search for the list with the given Id
var listOfSamples = finalList.Where(fl => fl.IdOfList == newItem.IdOfSample).FirstOrDefault();
if (listOfSamples == null)
{
// not found
// add new List with the new item in final list
finalList.Add(new ListOfSamples {IdOfList = newItem.IdOfSample, SampleList = new List<Sample>{newItem}} );
}
else
{
// found
// add the new item into the found list
listOfSamples.SampleList.Add(newItem);
}
If you replace ListOfSamples with a Dictionary<int, List<Sample>> then you will gain the ability to do a lookup in O(1) time and guarantee that the ids at the top level are unique. and then you can just add stuff like this.
Dictionary<int, List<Sample>> FinalList = new Dictionary<int, List<Sample>>();
Sample NewItem = new Sample()
{
IdOfSample = 12345,
SampleName = "Some name"
};
List<Sample> list;
if (!FinalList.TryGetValue(NewItem.IdOfSample, out list))
{
list = new List<Sample>();
FinalList.Add(NewItem.IdOfSample, list);
}
list.Add(NewItem);
TryGetValue will see if the dictionary has an entry for the key you pass it and returns true if it does and false if it does not. If it does have an entry for the key it also assigns the value of the entry (in this case your list of samples) to the out parameter. So, we check if it returns false and in that case we create a new list and add it to the dictionary. Then we add the sample to the list that we either got from the dictionary, or just created and put in the dictionary.

How to add one List into another List

I am trying to add one list into another but it is giving me error of The best overloaded method match for 'System.Collection.Generic.List.AddRange(System.Collections.Generic.IEnumerable)' has some invalid arguments
My code is:
public ActionResult RegisteredEvent(string Cno)
{
if (Request.IsAjaxRequest())
{
List<tblEvent> eventlist = new List<tblEvent>();
List<RegisteredEvent> list = new List<RegisteredEvent>();
var db = new clubDataContext();
int[] eventIds = (from m in db.EventRegistrations where m.Cno == Cno select m.Event_Id).ToArray();
int i = 1;
foreach (var item in eventIds)
{
list = (from m in db.tblEvents
where item.Equals(m.EventId)
select new RegisteredEvent()
{
id = m.EventId,
caption = m.Caption,
description = m.Description,
date = m.Date.ToString()
}).ToList();
eventlist.AddRange(list); //Here I am getting error
}
ViewBag.eventDetail = eventlist;
return PartialView("RegisteredEvent");
Simply speaking, you can only concatenate lists of the same type.¹
eventlist is a List<tblEvent>
list is a List<RegisteredEvent>
¹ This is not entirely correct: Since IEnumerable is covariant, it is actually possible to add entries of a List<S> to a List<T>, if S is a subtype of T.
The T in List<T> needs to have the same type or inherent from the same base type
List<RegisteredEvent> eventlist
List<RegisteredEvent> list
or
List<tblEvent> eventlist
List<tblEvent> list
You can use IEnumerable.Select as this (I don't know the structure of tblEvent, so adapt this at your code.
eventlist.AddRange(list.Select(x => new tblEvent{ id = x.id, caption = x.caption, ... }));
But the best way is to create directly a tblEvent
//the list sent to View
eventlist = (from m in db.tblEvents
where item.Equals(m.EventId)
select new tblEvent() //here
{
id = m.EventId,
caption = m.Caption,
description = m.Description,
date = m.Date.ToString()
}).ToList();

Categories

Resources