c# collections and re-numbering not working as expected - c#

Hi i'm trying to setup simple test data.
I simply want to take a collection which is smallish and make it bigger by add itself multiple times.
After I;ve added them together i want to re-number the property LineNumber
so that there are no duplicates and that it goes in order. 1,2,3,4....
no matter what i try it doesn't seem to work and i cant see the mistake.
var sampleTemplateLine = dataContext.TemplateFileLines.ToList();
*//tired this doesnt work either*
//List<TemplateFileLine> lineRange = new List<TemplateFileLine>();
//lineRange.AddRange(sampleTemplateLine);
//lineRange.AddRange(sampleTemplateLine);
//lineRange.AddRange(sampleTemplateLine);
//lineRange.AddRange(sampleTemplateLine);
var allProducts = sampleTemplateLine
.Concat(sampleTemplateLine)
.Concat(sampleTemplateLine)
.Concat(sampleTemplateLine)
.ToList();
int i = 1;
foreach (var item in allProducts)
{
item.LineNumber = i;
i++;
}
this doesnt seem to work either
//re-number the line number
var total = allProducts.Count();
for (int i =0; i < total; i++)
{
allProducts[i].LineNumber = i+1;
}
PROBLEM: below RETURN 4 when i'm expecting 1
var itemthing = allProducts.Where(x => x.LineNumber == 17312).ToList();

You are adding the same objects multiple times. You wold have to add new objects or clone the ones you have.

The problem is they are pointing the same object. So if you change a property it changes all the pointed objects at the same
You can use Clone method if it exist, if not you can create your own Clone method like in this question.

Related

ASP.NET adding data to class in loop

I have this code here:
for (int i = 0; i < reader.FieldCount; i++)
{
RedBlue item = new RedBlue();
if (reader.GetName(i).ToString().Contains("BID"))
{
item.baselinefinish = reader.GetValue(i).ToString();
}
if (reader.GetName(i).ToString().Contains("AID"))
{
item.actualenddate = reader.GetValue(i).ToString();
}
redBlue.Add(item);
}
What I am trying to do loop through data and add it to a class, but my problem is in my class I have two strings and I want to populate each string like this (first string gets the first item in the loop, the second string get the second item in the loop, and keep going like that, so instead of each one in the loop, for every two items in the loop add them to the string and continue on....I really hope this makes sense. Anyone know how I would accomplish this?
Currently what is happening, is it will add one of the strings to the class and then add the second string to a new class.
You can use Automapper and do something like this :
(adapted from what I remember of this framework, the docs here and your example)
// Configure AutoMapper
Mapper.Initialize(cfg =>
cfg.CreateMap<YourReaderClass, RedBlue>()
.ForMember(dest => dest.baselinefinish , opt => opt.MapFrom(src => src.BID))
.ForMember(dest => dest.actualenddate , opt => opt.MapFrom(src => src.AID))
// Perform mapping
RedBlue item = Mapper.Map<YourReaderClass, RedBlue>(reader);
You do the configuration once somewhere and then you can perform as many mapping you want. Of course, you have to manually indicate which field is mapped to which field with as many ForMember as you need.
EDIT
Actually, you could of course still do it without 3rd party, as you were thinking. To solve the specific problem with your method :
Currently what is happening, is it will add one of the strings to the
class and then add the second string to a new class.
(by the way, you mean instance of your class (object), not class )
Of course this happening, because you are creating new objects each time you iterate your loop !
If you do it like this, it should work :
// instantiate your object once, before the loop :
RedBlue item = new RedBlue();
for (int i = 0; i < reader.FieldCount; i++)
{
if (reader.GetName(i).ToString().Contains("BID"))
{
item.baselinefinish = reader.GetValue(i).ToString();
}
if (reader.GetName(i).ToString().Contains("AID"))
{
item.actualenddate = reader.GetValue(i).ToString();
}
}
// now you have one object named 'item' which should be what you want.
Not sure I follow, but right now you are creating a new object at every iteration and therefore each object will have only either string.
If your data is as you say, containing BID every second and AID every second element, as a poor mans solution, you could simply increment the i after adding the first string.
for (int i = 0; i < reader.FieldCount; i++)
{
RedBlue item = new RedBlue();
if (reader.GetName(i).ToString().Contains("BID"))
{
item.baselinefinish = reader.GetValue(i).ToString();
i++;
}
if (reader.GetName(i).ToString().Contains("AID"))
{
item.actualenddate = reader.GetValue(i).ToString();
}
redBlue.Add(item);
}
Or maybe I'm missing something?
Not sure if I follow your idea, but you can use even or odd index number to represent the first and second item on the loop.
Something like that:
for (int i = 0; i < reader.FieldCount; i++)
{
RedBlue item = null;
//if it's even index number
if(i % 2 == 0){
item = new RedBlue();
redBlue.Add(item);
if (reader.GetName(i).ToString().Contains("BID"))
item.baselinefinish = reader.GetValue(i).ToString();
}else{
if (reader.GetName(i).ToString().Contains("AID"))
item.actualenddate = reader.GetValue(i).ToString();
}
}

Matching lisboxes items and creating result

I am creating an Exam system in c#. I am creating result, i have answers in a listbox1 and correct answers in another listbox2, my issue is values in the listboxes should be compared and result should be generated on its base. If half the values match student is pass otherwise fail.
My code for this is following but it does not work.
for(int intCount = 0; intCount < listBoxSanswers.Items.Count;intCount++)
{
for (int intSubCount = 0; intSubCount < listBoxActAnswers.Items.Count; intSubCount++)
{
if (listBoxActAnswers.Items[intCount].ToString() == listBoxActAnswers.Items[intSubCount].ToString())
{
listBox3.Items.Add(listBoxActAnswers.Items[intCount].ToString());
}
}
}
If you want to use your approach, than you have to change one of the two lists to listBoxSanswers
If you want a shorter way, without the loops, you can try this line:
listBox3.Items.AddRange(listBoxActAnswers.Items.Cast<string>().ToList().Intersect(listBoxSanswers.Items.Cast<string>().ToList()).ToArray());
EDIT:
Oh okay, so you have a DataTable as a DataSource.
Than you can do it this way:
listBox3.Items.AddRange(listBoxActAnswers.Items.Cast<DataRowView>().Select(r => r[0]).ToList().Intersect(listBoxSanswers.Items.Cast<DataRowView>().Select(r => r[0]).ToList()).ToArray());
Maybe you should adapt Select(r => r[0]) to the right column which is your DisplayMember.

Getting a string to be a variable name

I found this question but it's being used with an XML file so I don't really understand what is going on.
What I want to do is get my list of objects to get populated in my for loop. Right now I have this:
for (int i = 0; i < dogs.Length; i++)
{
dogs[i] = new Dog();
}
dogs[0].PictureBox = picDog0;
dogs[1].PictureBox = picDog1;
dogs[2].PictureBox = picDog2;
dogs[3].PictureBox = picDog3;
I want to do something like this:
for (int i = 0; i < dogs.Length; i++)
{
dogs[i] = new Dog();
dogs[i].PictureBox = StringToVariable("picDog" + i);
}
PictureBox is a property field in case that makes a difference.
StringToVariable() is the thing I don't know about. I don't even know what it would be called to search for it.
It's impossible to say for sure without a good, minimal, complete code example. But I would expect that the following statement should work in your scenario:
dogs[i].PictureBox = (PictureBox)Controls.Find("picDog" + i, true)[0];
That will search the children of the current control (which I assume in this case is your Form subclass) for each control in turn. This is somewhat inefficient, as it has to search the controls collection for each item, but as long as you have a relatively small number of items, this is likely not a problem.
Depending on how your Form is set up, the following might also work:
string prefix = "picDog";
foreach (PictureBox pictureBox in Controls.OfType<PictureBox>())
{
if (pictureBox.Name.StartsWith(prefix))
{
int index;
if (int.TryParse(pictureBox.Name.Substring(prefix.Length), out index))
{
dogs[index] = pictureBox;
}
}
}
That version inspects each child control just once, attempting to parse an index appended to the initial text of "picDog", and if it's successful, using that index to assign to your array directly. This has the advantage of scaling well to larger lists of controls, but may be overkill in your case.
Note that in both of the above examples I've left out any error checking. In either example, you would probably want to add some kind of handling in case (for the first example) the desired control couldn't be found, or (for the second example) if you find a control for which you can't parse the index, or fail to fill in one of the elements of the dogs array.
If for some reason neither of the above examples seem to work for you, please edit your post so that it includes a better code example.
Sometimes a simple solution can work well. How about this?
var picDogs = new [] { picDog0, picDog1, picDog2, picDog3 };
for (int i = 0; i < dogs.Length; i++)
{
dogs[i] = new Dog();
dogs[i].PictureBox = picDogs[i];
}
You could even do this:
var dogs = new [] { picDog0, picDog1, picDog2, picDog3 }
.Select(picDog => new Dog() { PictureBox = picDog })
.ToArray();

How do I create a Dictionary<int, EntityState>, and add values inside a for loop?

So, I hope this is simple. I'm coming up with a way to store disconnected entities (due to my case being quite peculiar), and for it to work, I'd like to create a Dictionary with those values inside a for loop.
But I'm getting "An item with the same key" has been added problem, which I do not know why.
I've tried the following:
Dictionary<int, EntityState> StateProduct = new Dictionary<int, EntityState>();
for (int s = 0; s < userProducts.Count; s++ ) //userProducts.Count had value of 3
{
StateProduct.Add(s, EntityState.Modified);
}
But I get the error:
In which:
I really really do not know what's going on..
Edit: Here is the complete code
var dbIboID = dbs.OrderDB.Where(x => x.OrderID == Order[0].OrderID).FirstOrDefault();
if(dbIboID.IboID != uid)
{
return false;
}
//2nd Step:
//2.0 Attach it. Yes I know it sets it as unchanged. But let me do the magic trick!!!
dbIboID.OrderProcess = Order.ToList(); //CHANGED
dbs.OrderDB.Attach(dbIboID);
//2.1 Extract original values from the database.
var originalProducts = dbs.OrderProcessDB.Where(x => x.OrderProcessID == Order[0].OrderProcessID).ToList();
var userProducts = Order.ToList();
//This is a dictionary which will be used to set all other entities with their correct states!
Dictionary<int, System.Data.Entity.EntityState> StateProduct = new Dictionary<int, System.Data.Entity.EntityState>();
//2.3 Find new added products. addedProducts = userProducts[key] - originalProducts[key]
if(userProducts.Count > originalProducts.Count)
{
for (int i = originalProducts.Count - 1; i < userProducts.Count; i++ )
{
StateProduct.Add(i, System.Data.Entity.EntityState.Added);
}
}
//2.3 Find Deleted products = originalProducts - userProducts. Do reverse of the addedProducts
else
{
for (int i = userProducts.Count - 1; i < originalProducts.Count; i++)
{
StateProduct.Add(i, System.Data.Entity.EntityState.Deleted);
}
}
//2.4 Find modified products modifiedProducts = [userProducts - addedProducts] different originalProducts
//This is not 100% fool proof. Because there will be times that I will always have a modification,
// when objects remained unchanged.
for (int s = 0; s < userProducts.Count; s++ )
{
StateProduct.Add(s, System.Data.Entity.EntityState.Modified);
}
//2.5 Painting Process:
for (int i = 0; i < dbIboID.OrderProcess.Count(); i++ )
{
dbs.DB.Entry(dbIboID.OrderProcess[i]).State = StateProduct[i];
}
The code as you have shown it should not produce that exception, because the dictionary was allocated immediately prior to the loop, and thus should be empty, and the items being added all are unique integers.
My guess is that the dictionary already had some values in it. If so, then using Add to set a value will throw an ArgumentException, since the value corresponding to that key can only be replaced, not added, for the Dictionary class only allows one value per key.
So, if you expect the dictionary not to already have a value for a key, and want an error exception to be thrown if it does, do:
StateProduct.Add(s, EntityState.Modified)
If you want to add or replace a value, do:
StateProduct[s] = EntityState.Modified;

List<List> confusion

snippets of my code
List<List<optionsSort>> stocks = new List<List<optionsSort>>();
optionsSort tempStock1 = new optionsSort();
List<optionsSort> stock = new List<optionsSort>();
then some code,
for (int j = 1; j < optionsSt.Count; j++)
{
if (optionsSt[j].isin == optionsSt[j - 1].isin)
{
tempStock1.name = optionsSt[j].name;
tempStock1.date = optionsSt[j].date;
tempStock1.strike = optionsSt[j].strike;
tempStock1.size = optionsSt[j].size;
tempStock1.isin = optionsSt[j].isin;
tempStock1.callPut = optionsSt[j].callPut;
stock.Add(tempStock1);
}
else
{
stocks.Add(stock);
k = k + 1;
stock.Clear();
tempStock1.name = optionsSt[j].name;
tempStock1.date = optionsSt[j].date;
tempStock1.strike = optionsSt[j].strike;
tempStock1.size = optionsSt[j].size;
tempStock1.isin = optionsSt[j].isin;
tempStock1.callPut = optionsSt[j].callPut;
stock.Add(tempStock1);
}
}//endfor
Basicly, im going through a large list to sort elements into groups, a new List name stocks.
now the problem is, when I add to stocks all elements contained in the list stock and then clear stock on the next line to start again, I delete all the elements I have stored in stocks.
Any Ideas. Do I have to index stocks like stocks[i].Add(stock) so each block of similar stocks is an element in stocks.
Thanks for any help.
The problem is that List<T> objects, like all classes in .NET, are reference types. That means that every time you add stock to stocks you aren't adding a new list, you are only adding a reference to the same list in memory. So when you later call Clear, that is reflected both in your variable stock and in all other references in stocks.
You can resolve this by making a shallow copy of stock every time you add it to stocks:
stocks.Add(stock.ToList());
You're not creating a new list, you're using one list, and filling it and clearing it repeatedly. Since your outer list contains only one list, repeated multiple times, that list will have the same contents in every instance. That is, when you clear your list, you can no longer access the old contents, even if you try to access them from inside the outer list.
What you need to do is to change this line:
stock.Clear();
To this:
stock = new List<optionsSort>();
That is what you really meant. :)

Categories