converting array to custom list - c#

In my app I am writing data into a text file by converting a list into an array, later on I want to load it by converting it to the same list type and return it like that.
My code:
public abstract class PhoneBookCore
{
protected string _group;
public PhoneBookCore(string group)
{
this._group = group;
}
}
public class Group : PhoneBookCore
{
private List<PhoneBookCore> elements = new List<PhoneBookCore>();
public List<PhoneBookCore> elementsList {
get { return new List<PhoneBookCore>(elements); }
}
public Group(string name)
: base(name)
{
}
class DataOptions
{
public void Save(Group g)
{
string[] lines = g.elementsList.ConvertAll(p => p.ToString()).ToArray();
File.WriteAllLines(path, lines);
}
public Group Load()
{
string[] buffer = File.ReadAllLines(path); // ----> How do I convert it back
// to list of type group?
return ;
}
}
How do I convert it back to list of type group?

Maybe (assuming that you want to pass the whole line to the Group-constructor)
List<Group> allgroups = File.ReadLines(path)
.Select(l => new Group(l))
.ToList();
Note that I've used File.ReadLines which returns a streaming IEnumerable<string> instead of a string[], you can also read all into memory at once with File.ReadAllLines.
But why do you always create a new list in the elementsList property? Just return elements.
Edit If you want to create one group and set the elementsList from the lines, you need to provide the setter of the property first:
private List<PhoneBookCore> _elementsList = new List<PhoneBookCore>();
public List<PhoneBookCore> ElementsList
{
get { return _elementsList; }
set { _elementsList = value; }
}
Then you can initialize and set the group on this way:
Group g = new Group(path); // i have no idea
g.ElementsList = File.ReadLines(path)
.Select(l => new PhoneBookCore(l))
.ToList();
return g;

You're wanting to project each string item in your buffer list to a new PhoneBookCore instance. Since you're already using LINQ extensions, the following should suffice:
elementsList = buffer.Select(s => new PhoneBookCore(s)).ToList();

Related

sort custom array list with a specific field

i would like to sort by postal address but i am unable to i have seen some Linq functions tried them but i can't seem to get all the required parameters needed.
for example i saw this one example
list.Sort((p, q) => p.Category.CompareTo(q.Category)); /*has and error that says cannot convert lamba expressions to type '|Comparer' because it is not a delegate*/
but i dont seem to understand how to use it.
MyCustomList.cs
class MyCustomList
{
private string name;
private string postalAddress;
public MyCustomList(string name, string postalAddress)
{
this.name = name;
this.postalAddress = postalAddress;
}
//getters and setters
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
public string PostalAddress
{
get
{
return postalAddress;
}
set
{
postalAddress = value;
}
}
}
Form1.cs
ArrayList list = new ArrayList();
list.Add(new MyCustomList("A somename","A Fake Postal Address");
list.Add(new MyCustomList("B somename","B Fake Postal Address");
list.Sort(); // Sort by Postal adress
Do you really need to use ArrayList?
It's a relic from the pre-generics days of .NET, and you should really be using an implementation of IEnumerable<T> where possible e.g. List<T>.
LINQ operates on IEnumerable<T>, so won't work with your ArrayList, and the method you are looking for is OrderBy or OrderByDescending.
Example:
var list = new List<MyCustomList>();
list.Add(new MyCustomList("A somename","A Fake Postal Address"));
list.Add(new MyCustomList("B somename","B Fake Postal Address"));
list.OrderBy(cl => cl.Postcode); // Sort by Postal address
First stop using ArrayList - its as good as obsolete.
Either using Array like this
var list = MyCustomList[2];
list[0] = new MyCustomList(...
list[1] = new MyCustomList(....
or use something like the List<T> class
var list = new List<MyCustomList>();
list.Add(new MyCustomList(...
list.Add(new MyCustomList(...
If you use array then the Sort function that takes an instance of Comparison<T> is static
see the documentation here https://learn.microsoft.com/en-us/dotnet/api/system.array.sort?view=netframework-4.8#System_Array_Sort__1___0___System_Comparison___0__
you need to call it like so:
Array.Sort(list, (a,b) => a.PostalAddress.CompareTo(b.PostalAddress))
or use linq on your List or Array and use OrderBy
var orderedList = list.OrderBy(a => a.PostalAddress);
Already approved by many https://stackoverflow.com/a/57371579/6923146
For order wise sorting with a specific field in c# using linq
list = list.OrderByDescending(x => x.Name).ToList();
list = list.OrderBy(x => x.Name).ToList();
//list.OrderBy(x => x.YourClassSpecificField).ToList()
Example:
please try to run following code in fiddle :
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
List<MyCustomList> list = new List<MyCustomList>();
list.Add(new MyCustomList("A somename", "A Fake Postal Address"));
list.Add(new MyCustomList("B somename", "B Fake Postal Address"));
//list.Sort();
Console.WriteLine("descending order");
list = list.OrderByDescending(x => x.Name).ToList();
foreach (MyCustomList o in list)
{
Console.WriteLine(o.Name + " -- " + o.PostalAddress );
}
Console.WriteLine("ascending order");
list = list.OrderBy(x => x.Name).ToList();
foreach (MyCustomList o in list)
{
Console.WriteLine(o.Name + " -- " + o.PostalAddress );
}
}
public class MyCustomList
{
private string name;
private string postalAddress;
public string Name
{
get { return name; }
set { name = value; }
}
public string PostalAddress
{
get { return postalAddress; }
set { postalAddress = value; }
}
public MyCustomList(string name, string postalAddress)
{
this.name = name;
this.postalAddress = postalAddress;
}
}
}

Separate class for the same purpose

I have this class
public class BlessingDTO
{
public List<string> BlessingCategoryName;
public List<string> Blessings;
}
I am Getting the response of the two lists this way:
public async Task<List<BlessingDTO>> GetBlessing(string UserType)
{
string blessing = "Blessing_" + UserType;
List<BlessingDTO> results = new List<BlessingDTO>();
using (DTS_OnlineContext context = new DTS_OnlineContext())
{
var items = await context.Messages.AsNoTracking().Where(x => x.MessageContext == blessing).GroupBy(x=>x.GroupKey).Select(b=>b.OrderBy(x=>x.Sort)).ToListAsync();
if (items.Count() > 0)
{//Notes.Select(x => x.Author).Distinct();
results = items.ToList().ConvertAll(x => new BlessingDTO()
{ BlessingCategoryName = x.ToList().Select(y => y.MessageName).Distinct().ToList(),
Blessings = x.ToList().Select(y => y.MessageText).ToList()
});
}
}
return results;
}
if I am changing the class, for my porpuse to be:
public class BlessingDTO
{
public List<string> BlessingCategoryName;
public List<bless> Blessings;
}
public class bless
{
public string text;
public int length;
}
how can I initialize the new class ?
Blessings = new bless
won't give the results. how can I save the data to bring them in the response
Let's focus in this part:
items
.ToList()
.ConvertAll(x =>
new BlessingDTO()
{
BlessingCategoryName = x.ToList().Select(y => y.MessageName).Distinct().ToList(),
Blessings = x.ToList().Select(y => y.MessageText).ToList()
}
);
where items is probably a List<List<Message>>, thus x being a List<Message>.
Now what is causing an error is the following: Blessings = x.ToList().Select(y => y.MessageText).ToList(). This creates a new list for the list of messages, then selects the MessageText from that list, which results in IEnumerable<string>. In the end a new list is created for these strings. This list of strings isn't assignable to List<bless>, thus will generate an error.
What you want is a result of List<bless>, so we need to convert the List<Message> list into a List<bless> somehow. We know how to do that, namely with a select: x.Select(message => new bless()).ToList(). All we have to do is fill in the properties of bless: x.Select(message => new bless { text = message.MessageText }).ToList(). The other property is up to you.
You can initialise the list like this:
public class BlessingDTO
{
public List<string> BlessingCategoryName;
public List<bless> Blessings = new List<bless>();
}
Although, I would recommend these fields are changes to properties, as that is more idiomatic in C#
public class BlessingDTO
{
public List<string> BlessingCategoryName {get;set;}
public List<bless> Blessings {get;set;} = new List<bless>();
}

LINQ query to return collection of original object with a transformed property

I currently have working code
foreach (var item in list)
{
item.Property1= SomeFunction(item.Property1);
}
return list;
I'd like to convert this into a LINQ query but I'm not quite sure how to. I suspect I need to use a .Select but I'm not sure how to do that properly. My attempt was to try:
return list.Select(r => SomeFunction(r.Property1));
but of course that only returned a collection of Properties whereas I want a collection of the original object with an altered property within it.
I think this is probably a bad idea in general, but here you go ...
You want something like list.Select(x => { SomeFunction(x); return x; }); where SomeFunction is a function to transform the property you want.
Full example:
public class A { public int Data { get; set; } }
public void SomeFunction(A a)
{
a.Data *= 2;
}
var listy = new List<A>() {
new A() { Data = 3 },
new A() { Data = 5 }
};
listy.Select(x => { SomeFunction(x); return x; })
output (C# Interactive shell):
Enumerable.WhereSelectListIterator<Submission#9.A, Submission#9.A> { Submission#9.A { Data=6 }, Submission#9.A { Data=10 } }
Assuming list if of type List<>:
list.ForEach(x => x.Property1 = SomeFunction(item.Property1));
But what is wrong with foreach anyway?

Issue displaying LINQ query results in a grid in C#

I received some help here with the following LINQ query, but am still struggling with it. The result I'm trying to obtain is to display some attributes and their values from an xml file in a DataGridView control. I'm calling my method from a button click and am trying to pass back the list for display in the grid. Here is an example of the row:
<z:row CenterCode="JAX" CenterName="Jacksonville" Version="1.0" NextExport="66742" NextImport="29756" LastImportTime="2015-06-10T14:48:33" FtpProxyServer="" FtpUserName="" FtpPassword="" ResetImportID="False"/>
Here is the method:
public static List<string[]> MonitorCounts(string upperLimit)
{
// Load xml
XDocument xmldoc = XDocument.Load(#"c:\XML\Configuration.xml");
XNamespace z = "#RowsetSchema";
Int32 limit = Convert.ToInt32(upperLimit);
var elementQuery = xmldoc.Descendants(z + "row").Where(e => (long?)e.Attribute("NextExport") > limit | (long?)e.Attribute("NextImport") > limit);
var attributes = elementQuery.Select(e => e.Attributes().Select(a => new KeyValuePair<string, string>(a.Name.LocalName, (string)a)).ToList()).ToList();
return attributes;
}
My questions are how to select only specific attributes and values in attributes. If I do something like this:
var attributes = elementQuery.Select(e => e.Attributes("CenterName").Select(a => new KeyValuePair<string, string>(a.Name.LocalName, (string)a)).ToList()).ToList();
then this is returned:
[0] = {[CenterName, Jacksonville]}
I need to select this and 4 others. I'm also getting a convrsion error - Cannot implicitly convert type 'System.Collections.Generic.List<System.Collections.Generic.List<System.Collections.Generic.KeyValuePair<string,string>>>' to 'System.Collections.Generic.List<string[]>. Appreciate any pointers to help me along.
You can use an anonymous type:
var attributes =
elementQuery.Select(e => new
{
CenterName = (string)e.Attribute["CenterName"],
Version = (string)e.Attribute["Version"],
// more attributes
}).ToList();
You can't however return this from the method in a useful way. So if you really need both the attribute name and the attribute value as strings, try this approach instead:
var attributes =
elementQuery.Select(e => new []
{
Tuple.Create("CenterName", (string)e.Attribute["CenterName"]),
Tuple.Create("Version", (string)e.Attribute["Version"]),
// more attributes
}).SelectMany(x => x).ToList();
The return type of your method now has to be List<Tuple<string, string>>.
And finally, if you actually need a List<string[]> as the return type, use this code:
var attributes =
elementQuery.Select(e => new []
{
new [] { "CenterName", (string)e.Attribute["CenterName"] },
new [] { "Version", (string)e.Attribute["Version"] },
// more attributes
}).SelectMany(x => x).ToList();
I solved my own problem. Here is what I did:
Created a class for the attributes needed:
public class dataRow
{
public string CenterName { get; set; }
public string CenterCode { get; set; }
public string NextImport { get; set; }
public string NextExport { get; set; }
public string LastImportTime { get; set; }
}
Selected the results into it:
List<dataRow> dataRows = elementQuery.Select( e => new dataRow
{ CenterName = (string)e.Attribute("CenterName"),
CenterCode = (string)e.Attribute("CenterCode"),
NextImport = (string)e.Attribute("NextImport"),
NextExport = (string)e.Attribute("NextExport"),
LastImportTime = (string)e.Attribute("LastImportTime") }).ToList();
Changed my method to return the correct object:
public static List<dataRow> MonitorCounts(string upperLimit)
Set my grids datasource to the method return:
dataGridView1.DataSource = xmlProcessing.MonitorCounts(tbxUpperLimit.Text.ToString());
return dataRows;

Sort List by another, incomplete list

Okay I might overthink something here.
I try to sort a List by another List. Which works fine as long as another List contains all elements of List.
What would be a good apprach, if another List is incomplete and I'd like to keep the remaining elements at the end of List?
here an example:
public class Column
{
public int Id;
public string Name;
public string Something;
//...
}
public class Columns : IEnumerable<Column>
{
private List<Column> columnList = new List<Column>;
public void SortByName(List<Column> sortedIncompleteList)
{
var sorted = from incomplete in sortedIncompleteList
join current in columnList
on incomplete.FieldName equals current.FieldName
select current;
columnList = sorted.ToList();
}
//...
}
Maybe i am oversimplifying it, but why don't you use OrderBy if you want to sort? You can use following logic to get the items first which are in both collection:
public void SortByName(List<Column> sortedIncompleteList)
{
columnList = columnList
.OrderByDescending(c => sortedIncompleteList.Any(c2 => c.FieldName == c2.FieldName))
.ToList();
}
Update according to the comment: "but not in the order they actually appear in sortedIncompleteList":
public void SortByName(List<Column> sortedIncompleteList)
{
columnList = columnList
.OrderBy(c => {
int index = sortedIncompleteList.FindIndex(c2 => c.FieldName == c2.FieldName);
if (index == -1) return int.MaxValue;
return index;
})
.ToList();
}
I assume the elements in your lists are unique, since Column has an Id field, because my solution will remove duplicates.
public class Columns : IEnumerable<Column>
{
private List<Column> columnList = new List<Column>;
public void SortByName(List<Column> sortedIncompleteList)
{
columnList = sortedIncompleteList.Intersect(columnList)
.Concat(columnList.Except(sortedIncompleteList)).ToList();
}
//...
}
Intersect(), Concat() and Except() will preserve ordering...
You could use something like this:
var ids = sortedIncompleteList.Select(li => li.Id).ToList();
var ordered = from element in columnList
let index = ids.IndexOf(element.Id)
orderby index < 0 ? columnList.Count : index
select element;

Categories

Resources