I'm using foreach to transfer data from list to another but when adding value updated automatically to last value added. For example:
list1 = [1,2,3]
list2 = new List<Model>()
foreach(var item in list1) {
list2.Add(item)
}
the result in list2 is [ 3, 3, 3]
Actually example is below :
var _sizes = new List<ProductsSize>();
var _size = new ProductsSize();
if (model.Dynamic_ProductsSize.Count > 0)
{
foreach (var item in model.Dynamic_ProductsSize)
{
_size.SizeId = item;
_sizes.Add(_size);
}
}
model.ProductsSize = _sizes.ToList();
I need to know why it only takes the last item and what is the solution for this case
You only have one ProductsSize object:
var _size = new ProductsSize();
And you keep modifying that same object. All references to that object, including any list elements it's been added to, get updated when you modify that one object.
Instead, create your new object in the loop:
foreach (var item in model.Dynamic_ProductsSize)
{
var _size = new ProductsSize();
_size.SizeId = item;
_sizes.Add(_size);
}
That way each element in the list is a new object instead of the same object added multiple times.
Side note, you have a few things in the code which aren't necessary. Checking the length before the loop, for example, as well as converting a list to a list at the end.
In fact, I imagine all of the code shown can be shortened to simply this:
model.ProductsSize = model.Dynamic_ProductsSize.Select(p => new ProductsSize { SizeId = p }).ToList();
In which case you're also just converting one model property to another model property. Why not put this logic in the model itself and skip the whole thing?
public IEnumerable<ProductsSize> ProductsSize
{
get { return this.Dynamic_ProductsSize.Select(p => new ProductsSize { SizeId = p });
}
Unless there's a particular reason you want the same data twice in two different properties that isn't clear from this code, having one set of data and just different views/calculations/etc. of that data is often preferred.
Create a new object before adding it to the list. You can use the object initializer syntax to keep it concise:
if (model.Dynamic_ProductsSize.Count > 0)
{
foreach (var item in model.Dynamic_ProductsSize)
{
_sizes.Add(new ProductsSize(){SizeId = item});
}
}
Related
I'm exporting some data from database to excel using CLOSEDXML. I need to add the corresponding objects/item to each object in the 'newModelist' IQueryable and add all the object to new List. In my case new row were added in the list using list.add method, however the old record is replaced by the next row/object. I'm not quite what would be the correct way to implement this.
var getData = _db.Database.Where(y => y.identifier == Identifier);
var newModelist = new MainModel();
var listXML= new List<listXML>();
foreach(var item in getData)
{
newModelist.col1 = item.A;
newModelist.col2 = item.B;
newModelist.col2 = item.C;
listXML.Add(newModelist);
}
You need to understand what an instance is.
You are currently modifying the same object instance. And you are adding the same instance to the List on every iteration.
Since List only stores the reference to an instance, your List currently contains multiple references to the same instance. Each index will return the same element.
If you want individual object instances you must create each using the new keyword:
foreach(var item in getData)
{
var newModelist = new MainModel
{
col1 = item.A,
col2 = item.B,
col3 = item.C
};
listXML.Add(newModelist);
}
MainModel is a reference type and modifying the value will reflect in the all the references, so you need to create a new instance while setting the properties in the loop. Moving creation of newModelList to for loop would do
foreach(var item in getData)
{
var newModelist = new MainModel();
newModelist.col1 = item.A;
newModelist.col2 = item.B;
newModelist.col2 = item.C;
listXML.Add(newModelist);
}
I have the following problem. I have a list of strings and want to split these. After that, I want to give each Object Element a reference to an item of the List.
Example:
List<string> valueList = attr.Split(' ').ToList<string>();
This List has items like that:
name,string,age,int
For this example every Object needs to get 2 pieces of information, first the name (out of example: "name" or "age") and second the type (out of example: "string", "int").
Now I want to get an Object with this informations. So I created Objects and put these Objects into a List.
Example:
List<MyObject> listObjects = new List<MyObject>();
for (int i = 0; i < ValueList.Count; i++)
{
MyObject object = new MyObject();
if (ValueList.Any(s => s.StartsWith(modifier)) == true)
{
object.name = ValueList[i];
object.type = ValueList[i + 1];
}
listObjects.Add(object);
}
But with my solution, I'm getting a System.ArgumentOutOfRangeException. My explanation for this would be the foreach but I don't know a technique on how to get every item of the List of strings and add these to objects. Also what a problem is that 1 item of the List should have 2 elements (name, type) but with my method, I'm going through the foreach for every element. Is there any better way to do it in C# .Net Framework?
I suppose that you want something like this.
// Store your relevant keywords in a list of strings
List<string> datatypes = new List<string>{"string", "int"};
// Now loop over the ValueList using a normal for loop
// starting from the second elemend and skipping the next
for(int x = 1; x < ValueList.Count; x+=2)
{
// Get the current element in the ValueList
string current = ValueList[x];
// Verify if it is present in the identifiers list
if (datatypes.Contains(current)))
{
// Yes, then add the element before the current and the current to the MyObject list
MyObject obj = new MyObject;
obj.name = ValueList[x - 1];
obj.type = current;
listObjects.Add(obj);
}
}
I don't know where an error is. I have a list of element called TileModel with default values and ObservableCollection<TileModel> list
When I show a form in my view model I have to find in this list an element with the same name. If an element in the list exists, I copy this element in the ObservableCollection.
public ObservableCollection<TileModel> testList { get; set; }
List<TileModel> dsType = new List<TileModel>() {
new TileModel() { Text = "Alarms", IconImage = "Alarm.png",
NavigateType = typeof(Alarms) },
}
In a function I have this code:
foreach (string s in items)
{
TileModel dm = dsType.Where(d => d.Text.RemoveTextBetween("(", ")").Trim() == s)
.FirstOrDefault();
if (dm != null)
{
dm.Text = UpdateTextItem(dm.Text, iType);
testList.Add(dm);
}
}
UpdateTextItem changes the name Text to add the number of records. If I follow the code with F11, when I enter in the function dsType is the original. After dm.Text = UpdateTextItem(dm.Text, iType); dsType is changed this dm.text.
In my point of view dm is a new variable with in it a value of the list but isn't an instance of an element of the list. Then why do the code change my original dsType?
Thank you in advance.
That is because your class TileModel is a reference type. That means dm is just a reference to the original object.
By:
testList.Add(dm);
you add the reference to your testList - the object is the same if it gets changed, it also changes your object in your original list.
To Avoid this. You can add the Item like this: (If your ctor allows this)
var dm_new = new TileModel(dm);
dm_new .Text = UpdateTextItem(dm_new .Text, iType);
testList.Add(dm_new );
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.
I am creating two lists of objects. One "new" list, one "old list".
I want to take the value of one property from an object on the new list and set the property on the old list on the matching object the the new value.
//Original Solution
foreach (RyderQuestion quest in myList)
{
//compare it to every question in ryder questions
foreach (RyderQuestion oldQuestion in _ryderQuestions)
{
//if the question ids match, they are the same question, and should have the right selected option
//selecting the option sets the checkbox of the MultipleChoideQuestionControl
if (oldQuestion.QuestionID == quest.QuestionID)
{
oldQuestion.SelectedOption = quest.SelectedOption;
}
}
}
I am trying to convert it to LINQ to make it more effecient using joins, but how do i update the value directly?
var x = from quest in myList
join oldquest in _ryderQuestions
on new { quest.QuestionID, quest.ShowOn, quest.QuestionOrder }
equals new { oldquest.QuestionID, oldquest.ShowOn, oldquest.QuestionOrder }
select oldquest.SelectedOption = quest.SelectedOption;
This query returns the values to the x list, but I want to actually update the object in the old list instead.
Linq is for querying, not updating. You can join the two lists to line up the object to update, but you'll still have to loop to make the changes:
var query = from quest in myList
join oldquest in _ryderQuestions
on new { quest.QuestionID, quest.ShowOn, quest.QuestionOrder }
equals new { oldquest.QuestionID, oldquest.ShowOn, oldquest.QuestionOrder }
select new {oldquest, quest};
foreach(var item in query}
item.oldquest.SelectedOption = item.quest.SelectedOption
For example:
var x = from quest in myList
join oldquest in _ryderQuestions
on new { quest.QuestionID, quest.ShowOn, quest.QuestionOrder }
equals new { oldquest.QuestionID, oldquest.ShowOn, oldquest.QuestionOrder }
select new {quest , oldquest};
foreach(var item in x)
{
item.quest.SelectedOption = item.oldquest.SelectedOption;
}
You mean this?