Modifying List and comparing with previous value - c#

I have a list whose size is not fixed. In each iteration, the number of elements in the list may get decreased, increased or remain same but with different values.
In each iteration, I receive the newer list in a setter as following:
public List<int> IconsColor
{
get { return iconsColorList; }
set
{
newIconsColorList = new List<int>(value);
if (newIconsColorList.Count == iconsColorList.Count && newIconsColorList.All(iconsColorList.Contains))
return;
//Else
nIconsChanged = true;
//??????????????????????????
//?????????- How do I update Old list with New values
//Something like iconsColorList = newIconsColorList;
//but above line makes the If-condition true since both the lists are same now
}
}
How do I modify the elements of the previous list (iconsColorList) with new values (present in newIconsColorList)? And if the number of elements in the new list is greater than to that of the older list then, add the new element to the older list also.

So you want to merge both lists (update and add new):
public List<int> IconsColor
{
set
{
for (int i = 0; i < Math.Min(iconsColorList.Count, value.Count); i++)
{
if (value[i] != iconsColorList[i])
{
iconsColorList[i] = value[i];
nIconsChanged = true;
}
}
if (value.Count > iconsColorList.Count)
{
// append new items to the end of the list
iconsColorList.AddRange(value.Skip(iconsColorList.Count));
nIconsChanged = true;
}
}
}
Side-note: i hope the lack of a getter was just because it wasn't relevant. A property without a getter is not really useful and smells like fish. In this case it would just return iconsColorList;.

Related

What collection should i use if i need to control the position of item and need to be able to serialize the collection

i need a collection and i am not sure which one to use. I have used List before but i need to also be sure about the specific position. If user views an item A i will ads it to the collection and if he sees another item B i will add that item on top of the first one and so on, but the limit number fot he items is 3 so i would remove the first item, also i need to be able to seriliaze the collection. I have tried Dictionary, but i could use XmlSerializer, so i have tried to use Lst<KeyValue<>> and now i am trying an array like this. Also had a look on Queue but i have found out that using XmlSerializer could also be an issue. Any suggestion for what collection i can use?
class Program
{
static void Main(string[] args)
{
string[] myObjArray = new string[3] ;
if(myObjArray[0] == null)
{
myObjArray[0] = "article1";
Console.WriteLine(myObjArray[0]);
}
if (myObjArray[1] == null )
{
myObjArray[1] = "article2";
Console.WriteLine(myObjArray[1]);
}
if (myObjArray[2] == null)
{
myObjArray[2] = "article3";
Console.WriteLine(myObjArray[2]);
}
var input = Console.ReadLine();
myObjArray[0] = input;
Console.WriteLine(myObjArray[0]);
}
}
You can use a List<Item> and use the Index as position and methods Insert and Delete to achieve your goal. If the position if encapsulated in the entity, you can create methods to manage it.
So when you add an item you will check if the count is over than the allowed and delete the first if nedeed.
[Serializable]
public class MyList
{
private readonly List<Item> Items = new List<Item>();
public int Count { get { return Items.Count; } }
public int MaxCount { get; set; } = 0;
public void Add(Item item)
{
if ( MaxCount > 0 && Items.Count >= MaxCount )
Items.RemoveAt(0);
Items.Add(item);
}
public void Insert(int index, Item item)
{
Items.Insert(index, item);
}
public int FindById(int id)
{
for ( int index = 0; index < Items.Count; index++ )
if ( Items[index].Id == id )
return index;
return - 1;
}
// Add all over new methods and wrapping methods needed
}
This code use 0 to indicate that the max count is not considered, but if the list may not accept items, it can manage -1 for that, so 0 indicates that the list is closed.
Perhaps you can use a LinkedList that is searializable but you need to implement it for XML:
https://learn.microsoft.com/dotnet/api/system.collections.generic.linkedlist-1
How to Xml serialize a LinkedList?
So with that you can easily manage items as you wrote:
Add a cell between two cells.
Add a cell before a cell.
Add a cell after a cell.
Add a cell at the start.
Add a cell at the end.
Remove the first.
Remove the last.
And so on...
Hence you can add automatic delete the first cell if the count is over the allowed.
When should I use a List vs a LinkedList
LinkedList in C# - tutorialspoint.com
Linked Lists - dotnetcademy.net
C# | LinkedList Class - geeksforgeeks.org
Linked List Implementation in C# - geeksforgeeks.org

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 code add to linked list so you can print from the oldest to newest item?

Okay so I have to print out a linked list from the order I put it in. Each node refers to a ticket object, and the ticket object has its own print function that I can call upon. I can remove the start of the list and refer it to the next ticket, but have it coded so that it prints out the newest to oldest. I believe the problem lies in my code that allows me to add a ticket to the list:
private class TicketNode
{ //basic node
public TicketNode next;
public Ticket data;
public TicketNode(Ticket tic)
{
data = tic;
}
}
public void PrintAll()
{//Prints all tickets
TicketNode cur = first;
while (cur != null)
{
cur.data.PrintDescription();
cur = cur.next;
}
}
public void AddTicket(Ticket t)
{
TicketNode ticNode; //creates a new node
if (first == null) //for kick-starting the list
first = new TicketNode(t);
else
{
ticNode = new TicketNode(t); //initializes node
ticNode.next = first;
first = ticNode; //first.next is the ticket that was ticNode
}
}
ex: I put in the tickets with strings "Low", "Another Low", and "Final Low" and when I want to print it out I expect:
Low
Another Low
Final Low
Instead I get:
Final Low
Another Low
Low
If I were to remove to oldest ("Low") I should see something like this next time print:
Another Low
Final Low
Any ideas on a how to reorient the list?
The simplest solution would be to insert new items at the end of the list. To do that in O(1), you need to keep a pointer last to the last item in the list. When you insert a new item, you use that pointer to quickly get the last item, append the new item and update the pointer.
With that modification, you can iterate from first via next and actually get the items in their insert order.
While Adding element into linked list, you have find end of the list and there. Following code might be useful for you
AddTicket method is sholud be like this
void AddTicket(Ticket t)
{
TicketNode ticNode; //creates a new node
if (first == null) //for kick-starting the list
first = new TicketNode(t);
else
{
ticNodeNew = new TicketNode(t);
TicketNode ticNode; = first;
while(ticNode.next != null)
{
ticNode = ticNode.next;
}
ticNode.next = ticNodeNew;
}
}
}
In your linked list, the an item references the next oldest, etc. The most recent is first in the list, and the oldest items is at the end of the list. That is why when you run through the list in PrintAll() you get items youngest to oldest.
You need to print your list out in reverse order and an easy way of doing that is to use a Stack.
public void PrintAll()
{
var stack = new Stack<TicketNode>();
TicketNode cur = first;
while (cur != null)
{
stack.Push(cur);
cur = cur.next;
}
while (stack.Count > 0)
stack.Pop().data.PrintDescription();
}
MH09's solution which stores the list in oldest to youngest order is also valid. MH09's solution traverses the entire list on AddTicket(), my solution traverses the list in PrintAll(). You might want to choose which solution is better suited to you on the basis of performance. However in both cases the traversal is O(n).

Adding to columns based on length

I have a ListView with two columns, Boxes and Files. I'm adding items to a list of strings, and then populating the ListView with that list of strings. I want to make it so all items that are 8 characters long go into the Boxes column and all items that are 9 characters go into the Files column. So far, I've tried to iterate through using a for loop and utilize an if else statement to add the items, but I seem to be doing something wrong. Here's my current code:
public void PopulateItemsList()
{
BoxAndFileList.Items.Clear();
ScanIdBox.Text = string.Empty;
for (int i = 0; i < BoxNumberRepository._boxAndFileList.Count; i++)
{
var item = BoxNumberRepository._boxAndFileList.Item[i];
if (item.Length == 8)
{
BoxAndFileList.Items.Insert(0, item);
}
else
{
BoxAndFileList.Items.Insert(1, item);
}
}
}
I'm iterating through my list (_boxAndFileList) and trying to utilize Insert() to insert items into the specific index of the columns (Boxes is 0, Files is 1). I can clearly see that Item is a legitimate property of a string list, yet VS keeps saying that list contains no definition of it. How can I go about doing this? And also, I haven't received outside feedback on this way of doing things yet, so if there's a better way, please let me know.
Edit: BoxNumberRepository is a class that news up a list called _boxAndFileList. Code below:
public class BoxNumberRepository : Scan_Form
{
public static List<string> _boxAndFileList = new List<string>();
public void AddItem(string item)
{
_boxAndFileList.Add(item);
}
public void Delete(string item)
{
_boxAndFileList.Remove(item);
}
public IEnumerable<string> GetAllItems()
{
return _boxAndFileList;
}
}
Thanks to Alessandro D'Andria for that suggestion. That was correct. However, all the items are still just adding to the first column, even if they're 9 characters. How can I get 9 character items to add to the second column?
The problem that you are having is that you have to add both the box and file to the list item at the same time.
EDIT: Changed cartesian product to a left outer join.
EDIT: Added comments and fixed a syntax bug
private List<string> _boxAndFileList = new List<string> { "12345678", "123456789", "1234", "123456778" };
public void PopulateItemsList()
{
//clear the list
BoxAndFileList.Items.Clear();
//add the labels to the top of the listbox
BoxAndFileList.Columns.Add("Boxes");
BoxAndFileList.Columns.Add("Files");
//set the view of the list to a details view (important if you try to display images)
BoxAndFileList.View = View.Details;
//clear scan id box
ScanIdBox.Text = string.Empty;
//get all the items whos length are 8 as well as a unique id (index)
var boxes = _boxAndFileList.Where(b => b.Length == 8).Select((b, index) => new { index, b }).ToList();
//get all the items whos length are NOT 8 as well as a unique id (index)
var files = _boxAndFileList.Where(f => f.Length != 8).Select((f, index) => new { index, f }).ToList();
//join them together on their unique ids so that you get info on both sides.
var interim = (from f in files
join b in boxes on f.index equals b.index into bf
from x in bf.DefaultIfEmpty()
select new { box = (x == null ? String.Empty : x.b), file = f.f });
//the real trick here is that you have to add
//to the listviewitem of type string[] in order to populate the second, third, or more column.
//I'm just doing this in linq, but var x = new ListViewItem(new[]{"myBox", "myFile"}) would work the same
var fileboxes = interim.Select(x => new ListViewItem(new []{ x.box, x.file})).ToArray();
//add the array to the listbox
BoxAndFileList.Items.AddRange(fileboxes);
//refresh the listbox
BoxAndFileList.Refresh();
}
Your _boxAndFileList is a List<string> so you should be declare item as string type instead var type:
string item = BoxNumberRepository._boxAndFileList.Item[i];
All your code should be like this:
public void PopulateItemsList()
{
BoxAndFileList.Items.Clear();
ScanIdBox.Text = string.Empty;
for (int i = 0; i < BoxNumberRepository._boxAndFileList.Count; i++)
{
string item = BoxNumberRepository._boxAndFileList.Item[i];
if (item.Length == 8)
{
BoxAndFileList.Items.Insert(0, item);
}
else
{
BoxAndFileList.Items.Insert(1, item);
}
}
}

How to change each element of a List<long>?

I have a List of different DayTime (Ticks). I try to get a list of the time remaining from now to each time element.
List<long> diffliste = new List<long>(m_DummyAtTime);
// 864000000000 ≙ 24h
diffliste.ForEach(item => { item -= now; if (item < 0) item += 864000000000; });
// test, does also not work
// diffliste.ForEach(item => { item -= 500; });
However, the list is not changed. Do I miss something?
(now is DateTime.Now.TimeOfDay.Ticks)
var times = diffliste.Select(ticks => new DateTime(ticks) - DateTime.Now);
Will return a collection of TimeSpans between now and each time.
Without using Linq:
List<TimeSpan> spans = diffliste.ConvertAll(ticks => new DateTime(ticks) - DateTime.Now);
(modified as suggested by Marc)
You are changing a standalone copy in a local variable (well, parameter actually), not the actual value in the list. To do that, perhaps:
for(int i = 0 ; i < diffliste.Count ; i++) {
long val = diffliste[i]; // copy the value out from the list
... change it
diffliste[i] = val; // update the value in the list
}
Ultimately, your current code is semantically similar to:
long firstVal = diffliste[0];
firstVal = 42;
which also does not change the first value in the list to 42 (it only changes the local variable).
You cannot change the value of an item inside a foreach cycle.
You can do it using a classic for cycle or creating and assigning items to a new list.
for (int i = 0 ; i < diffliste.Count; i++)
{
long value = diffliste[i];
// Do here what you need
diffliste[i] = value;
}
The iteration var in a foreach cycle is immutable, so you cannot change it. You either have to create a new list or use a for cycle... see also here.

Categories

Resources