Checking which object appears most times in a list c# - c#

So i Have a temporary ListObject List used just to check the condition
class ListObject
{
public string Key { get; set; }
public int Value { get; set; }
public void Convert(string str)
{
Key = str;
}
}
and I'm writing a method supposed to check which name appears most times in another List of objects. The ListObject.Key gets the name assigned, while ListObject.Value stores the number of appearances. I want to check if the name was already stored from the List I'm holding the value in, and if yes, then increase the Value on the ListObject field which stores the name.
The thing is that i have no idea how to point the field which should be increased. I would need something like list[*index of the wanted name].Value += 1; How am i supposed to point the index? And should I use KeyValue pair instead of my ListObject class?

It looks like you're trying to re-invent a Dictionary<TKey,TValue>
var frequencyMap = new Dictionary<string,int>();
foreach(string item in itemList)
{
if (!frequencyMap.ContainsKey(item))
frequencyMap.Add(item, 0);
frequencyMap[item] += 1;
}

Related

C# Binary search

so I am trying to learn and practice binary search but unfortunately can not understand how binary search could work for a List of objects or just strings for example. It does not look that complicated when you deal with numbers. But how do u actually perform a binary search for instance with list of object which holds property name inside as a string value.
Binary search assumes sorted collection. So, you have to provide a compare(a,b) function. That function will return -1,0 or 1 as the result of the comparison. The function implementation for numbers or chars is trivial. But, you can implement a much more complex logic that takes one or more object properties into consideration. As long as you provide that function, you can sort any collection of the objects and you can apply binary search on that collection.
You would do it the same way as with numbers, the only difference is, that you access the property of the instance you are looking at.
For example items[x].Value instead of items[x].
Say you have a list of friends which use the Friend Class and you want to use a binary search to find if a friends exists in this list. Firstly, a binary search should only be conducted on a sorted list. Using lambda, you can order the list and then change it to an array. In this example I am collecting the input into from a textbox (which is looking for the name of the friend) after a button is clicked and then conducting the binary search. The Friend class must also implement IComparable.
class Friend : IComparable<Friend>
{
public string Name { get; set; }
public string Likes { get; set; }
public string Dislikes { get; set; }
public int Birthday { get; set; }
//Used for the binary search
public int CompareTo(Friend other)
{
return this.Name.CompareTo(other.Name);
}
}
class MainWindow
{
List<Friend> friends = new List<Friend>();
//other functions here populated the list
private void OnButtonClick(object sender, EventArgs e)
{
Friend[] sortedArray = friends.OrderBy(f => f.Name).ToArray();
int index = Array.BinarySearch(sortedArray, new Friend() { Name = tb_binarySearch.Text });
if (index < 0)
{
Console.WriteLine("Friend does not exist in list");
}
else
{
Console.WriteLine("Your friend exists at index {0}", index);
}
}
}
If the index returns as a negative number, the object does not exist. Otherwise it will be the index of the object in the sorted list.

Designing class with fields as string arrays

I'm not sure if this is the right title, but here goes.
I have a simple class with many fields and a method that checks these fields. The class looks like below. I removed the accessors for space.
So I call SetAlarms to set the fields to later use them with method AlarmsOk() and other methods. Everything worked fine since the datatable only had one row.
Now the datatable has two rows. So I was thinking of using a struct array to store these two rows. If I continued using the class fields, I'd set them as arrays I would need to initialize each string, which means that I would need to add 100 rows, one per field. One the other hand, I can have a struct array and initialize it two length of 2 with one line.
Is this correct?
public class Alarms
{
private string[] alarm0;
private string[] alarm1;
// to Alarm99
private string[] alarm99;
public void SetAlarms(DataTable AlarmsTable)
{
int currentRow = 0;
int rowCount = AlarmsTable.Rows.Count; //AlarmsTable has 2 rows
alarm0 = new string[rowCount];
alarm1 = new string[rowCount];
// to Alarm99
alarm99 = new string[rowCount];
foreach (DataRow row in AlarmsTable.Rows)
alarm0[currentRow] = Convert.ToString(AlarmsTable.Rows[currentRow]["Alarm0"]);
alarm1[currentRow] = Convert.ToString(AlarmsTable.Rows[currentRow]["Alarm1"]);
// to Alarm99
alarm99[currentRow] = Convert.ToString(AlarmsTable.Rows[currentRow]["Alarm99"]);
currentRow++;
}
}
public bool AlarmsOk()
{
//Check if alarms are OK, return true/false
}
}
If I understand correctly, I would rather use some AlarmData class and a List instead:
public class AlarmData
{
public string Alarm0 { get; set; }
...
public string Alarm99 { get; set; }
}
public class Alarms
{
private List<AlarmData> alarmData = new List<AlarmData>();
public void SetAlarms(DataTable AlarmsTable)
{
this.alarmData.Clear();
foreach (DataRow row in AlarmsTable.Rows)
{
var newData = new AlarmData();
newData.Alarm0 = Convert.ToString(AlarmsTable.Rows[currentRow]["Alarm0"]);
...
newData.Alarm99 = Convert.ToString(AlarmsTable.Rows[currentRow]["Alarm99"]);
this.alarmData.Add(newData);
}
}
public bool AlarmsOk()
{
//Check if alarms are OK, return true/false
}
}
So you have a class that correspond to your table (and an instance in your list for each row), which is easier to read IMO.
You can use array of arrays:
private string[][] alarm;
And use it:
alarm[0][currentRow] = value;
This seems like bad design to me. Your OP suggests you are crowbarring everything into a single table.
Rather than have a single Alarms class,I think you should have a singular Alarm class. This would store information about a single alarm entity only. Then whatever the object is that actually has the alarms (say a Foo) would have a collection of Alarm objects - so something like
public class Foo
{
public List<Alarm> Alarms { get; set; }
}
On the database side you would have a Foo table and an Alarm table. Your Alarm table will have a FooID column so you can link each one back to the Foo.

Can I get an element from a List<T> by string-based indexing in .Net? (I.E.: T val = List<T>["NameHere"])

In C#/.Net, I know that with a DataSet you can access a named table by DataSet.Tables[NameHere].
Is it possible to do this with a List (if the elements in the list have a property by which you can find them like that?)
I'm not talking about List<T>.Find(tVar => tVar.Prop == "NameHere"),
I want to just be able to say T val = List<T>["NameHere"].
Is that possible, and if so, how would I go about accomplishing this?
Also, as a kind of aside, I'm sure this has a proper name : What is it?
It is called "indexer", read more from here
You can create your own class which implement IList interface and add indexer to it.
Create a KeyedCollection<TKey,TValue> for your type:
public class SomeClass
{
public string Name { get; set; }
public string Value { get; set; }
}
public class SomeClassCollection : KeyedCollection<string,SomeClass>
{
protected override string GetKeyForItem(SomeClass item)
{
return item.Name;
}
}
[TestClass]
public class KeyedCollectionTests
{
[TestMethod]
public void Test()
{
var items = new SomeClassCollection
{
new SomeClass{Name = "Name 1", Value = "Value 1"},
new SomeClass{Name = "Name 2", Value = "Value 2"}
};
items["Name 1"].Value.Should().Be("Value 1");
items[1].Value.Should().Be("Value 2");
}
}
#Will You will add additional complication to your code base by rolling your own apart from any performance impact. I reckon your problem can be solved by utilising existing functions in .Net
There are 2 ways to solve your problem
Using List to point to your set of objects to allow you to index by int AND
Using a Dictionary to point to the same set of objects to allow you to index my string. An object can be reference by more than one collection
Using a DataTable with an Int column and a string column, put an index on each column and use the Find function. (Not sure if you could add an index on each columns like a db table as I haven't use DataTable for a long time but I'm sure you can look up MSDN documentation)

Returning an Object with a guid and string from a method

I have this method which i pass in a file name and file path in which i will be saving to.
The file is put in a for loop so that i save each page as a separate file. At the same time each page will contain a barcode that i am reading off. I want to store each barcode and file path in a list in which i return so i can use in a different method.
public __________ InputFile(string fileName, string filePath)
{
for(int page = 1; page <= fileName.PageCount; page++)
{
read barcode
save page as new file
}
return ___________;
}
I already have what i need to read and save the file i just want to know how do i set this up to return an object of the barcode and the path?
The basic answer would be to write your own class that stores the value and return a List of that type. If you don't want to write your own class, then you can look into using the System.Tuple<T,U> type.
EDIT:
Here's what the class might look like (class and property names can be changed to anything you'd like).
public class Result
{
public Guid Barcode {get; set;}
public string Value {get; set;}
}
In your method, create a new instance of List<Result>, and for each iteration of the loop, create a new instance of Result and add it to the list, then return the list.
Best option would be to create a class explicit to store these values and return an instance of your class.
public class MyResult
{
public Guid Barcode { get; set; }
public string Path { get; set; }
}
public MyResult InputFile(string fileName, string filePath) { ... }
Alternatively you could use a Tuple, then you would return Tuple<Guid, string> and create it with Tuple.Create(guid, path). You access the values with the properties Item1 and Item2. Due to this naming you really should use the first approach, as it is more explicit.
You could return an
IEnumerable<Tuple<Barcode, string>>
if you didn't want to have another class.
Either create your own object with 2 properties or use a Tuple
Tuple<GUID, string> tuple = new Tuple<GUID, string>();

remove duplicates items from a collection except its first occurance

I have a Collection of type string that can contain any number of elements.
Now i need to find out all those elements that are duplicating and find out only the first occurance of duplicating elements and delete rest.
For ex
public class CollectionCategoryTitle
{
public long CollectionTitleId { get; set; }
public bool CollectionTitleIdSpecified { get; set; }
public string SortOrder { get; set; }
public TitlePerformance performanceField { get; set; }
public string NewOrder { get; set; }
}
List<CollectionCategoryTitle> reorderTitles =
(List<CollectionCategoryTitle>)json_serializer
.Deserialize<List<CollectionCategoryTitle>>(rTitles);
Now i need to process this collection in such a way tat it removes duplicates but it must keep the 1st occurance.
EDIT:
I have updated the code and i need to compare on "NewOrder " property
Thanks
For your specific case:
var withoutDuplicates = reorderTitles.GroupBy(z => z.NewOrder).Select(z => z.First()).ToList();
For the more general case, Distinct() is generally preferable. For example:
List<int> a = new List<int>();
a.Add(4);
a.Add(1);
a.Add(2);
a.Add(2);
a.Add(4);
a = a.Distinct().ToList();
will return 4, 1, 2. Note that Distinct doesn't guarantee the order of the returned data (the current implementation does seem to return them based on the order of the original data - but that is undocumented and thus shouldn't be relied upon).
Use the Enumerable.Distinct<T>() extension method to do this.
EDIT: mjwills correctly points out that guaranteed ordering is important in the question, so the other two suggestions are not spec-guaranteed to work. Leaving just the one that gives this guarantee.
private static IEnumerable<CollectionCategoryTitle> DistinctNewOrder(IEnumerable<CollectionCategoryTitle> src)
{
HashSet<string> seen = new HashSet<string>();
//for one last time, change for different string comparisons, such as
//new HashSet<string>(StringComparer.CurrentCultureIgnoreCase)
foreach(var item in src)
if(seen.Add(item.NewOrder))
yield return item;
}
/*...*/
var distinctTitles = reorderTitles.DistinctNewOrder().ToList();
Finally, only use .ToList() after the call to DistinctNewOrder() if you actually need it to be a list. If you're going to process the results once and then do no further work, you're better off not creating a list which wastes time and memory.

Categories

Resources