I have 2 List collections. One contains numbers, the other names. There are twice as many numbers as names(always). I want to take the first name from the collection and the first two numbers from the other collection then put them together in a 3rd user collection of (VentriloUser). Then the second name needs to be matched with the 3rd and 4th numbers and so on.
I was thinking something with a for or foreach loop, but I can't wrap my head around it right now.
public class VentriloUser
{
public VentriloUser(string name, int seconds, int ping)
{
Name = name; Seconds = seconds; Ping = ping;
}
public string Name { get; set; }
public int Ping { get; set; }
public int Seconds { get; set; }
}
public class Ventrilo
{
public Ventrilo(string statusurl)
{
StatusURL = statusurl;
}
public string StatusURL { get; set; }
public string HTML { get; set; }
public List<VentriloUser> Users { get; set; }
private Regex findNumbers = new Regex("\\<td width=\"10%\" bgcolor=\"#\\w{6}\"\\>\\<font color=\"#000000\">\\<div style=\"overflow:hidden;text-overflow:ellipsis\"\\>-?\\d+\\<");
private Regex findNames = new Regex("\\<td width=\"20%\" bgcolor=\"#\\w{6}\"\\>\\<font color=\"#000000\">\\<div style=\"overflow:hidden;text-overflow:ellipsis\"\\>\\b\\w+\\<");
private WebClient wClient = new WebClient();
public void DownloadHTML()
{
HTML = wClient.DownloadString(StatusURL);
}
public List<int> GetNumbers()
{
var rawnumbers = findNumbers.Matches(HTML);
var numbers = new List<int>();
foreach (var rawnumber in rawnumbers)
{
var match = Regex.Match(rawnumber.ToString(), "\\>\\-?\\d+\\<");
string number = Regex.Replace(match.ToString(), "\\<|\\>", "");
numbers.Add(Convert.ToInt32(number));
}
return numbers;
}
public List<string> GetNames()
{
var rawnames = findNames.Matches(HTML);
var names = new List<string>();
foreach (var rawname in rawnames)
{
var match = Regex.Match(rawname.ToString(), "\\>\\w+<");
string name = Regex.Replace(match.ToString(), "\\<|\\>", "");
names.Add(name);
}
return names;
}
public List<VentriloUser> GenerateUsers()
{
var numbers = GetNumbers();
var names = GetNames();
var users = new List<VentriloUser>();
}
}
I am a hobbyist, but hope to pursue a career one day. Any help is much appreciated. Thank you for your time.
Using LINQ:
var users = names.Select((name,idx) => new VentriloUser(name, numbers[idx*2], numbers[idx*2+1]))
.ToList();
Using loops:
var users = new List<VentriloUser>();
for (int i = 0; i < names.Count; i++)
{
var name = names[i];
int j = i * 2;
if (j >= numbers.Count - 1)
break; // to be safe...
users.Add(new VentriloUser(name, numbers[j], numbers[j + 1]));
}
Related
Here are the full details of my code:
public partial class Form1 : Form
{
List<Sales> sales = new List<Sales>();
BindingSource bs = new BindingSource();
public Form1()
{
InitializeComponent();
LoadCSV();
bs.DataSource = sales;
dgvSales.DataSource = bs;
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void LoadCSV()
{
string filePath = #"c:\Users\demo\Task3_shop_data.csv";
List<string> lines = new List<string>();
lines = File.ReadAllLines(filePath).ToList();
foreach (string line in lines)
{
List<string> items = line.Split(',').ToList();
Sales s = new Sales();
s.TextBook = items[0];
s.Subject = items[1];
s.Seller = items[2];
s.Purchaser = items[3];
s.purchasedPrice = float.Parse(items[4]);
s.SalePrice = items[6];
s.Rating = items[7];
sales.Add(s);
}
}
}
}
my sales class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MichaelSACU301task3
{
internal class Sales
{
public string TextBook { get; set; }
public string Subject { get; set; }
public string Seller { get; set; }
public string Purchaser { get; set; }
public float purchasedPrice { get; set; }
public string SalePrice { get; set; }
public string Rating { get; set; }
}
}
I tried launching it but the error message keeps appearing can someone please help me fix this problem.
Use float.TryParse prior to assigning to purchasedPrice property, if the value can not be converted remember it in a list. In the example below the code to read file data is in a separate class which returns a list of sales and a list of int which is used to remember invalid lines where purchasedPrice data is invalid. You should also consider validating other data and also ensure proper amount of data after performing the line split.
public class FileOperations
{
public static (List<Sales>, List<int>) LoadSalesFromFile()
{
List<Sales> sales = new List<Sales>();
List<int> InvalidLine = new List<int>();
string filePath = #"c:\Users\demo\Task3_shop_data.csv";
List<string> lines = File.ReadAllLines(filePath).ToList();
for (int index = 0; index < lines.Count; index++)
{
var parts = lines[0].Split(',');
// validate purchase price
if (float.TryParse(parts[4], out var purchasePrice))
{
Sales s = new Sales();
s.TextBook = parts[0];
s.Subject = parts[1];
s.Seller = parts[2];
s.Purchaser = parts[3];
s.purchasedPrice = purchasePrice;
s.SalePrice = parts[6];
s.Rating = parts[7];
sales.Add(s);
}
else
{
// failed to convert purchase price
InvalidLine.Add(index);
}
}
return (sales, InvalidLine);
}
}
Call the above code in your form
var (salesList, invalidLines) = FileOperations.LoadSalesFromFile();
if (invalidLines.Count > 0)
{
// use to examine bad lines in file
}
else
{
// uses sales list
}
the error sis probably due the impossiability of float.Parse() parse the items[4] in float
you may track value of items[4] using brake point in VS
I have a problem about populating list<> elements. I tried to set a value to first element of list<> object but it didn't work. Here is my two classes:
CLASS
class hotel
{
public List<room> rooms = new List<room>();
}
class room
{
public string roomName;
}
Form1.cs
private void Form1_Load(object sender, EventArgs e)
{
string word = "example";
hotel[] h = new hotel[3];
for (int i = 0; i < h.Length; i++)
{
h[i] = new hotel();
h[i].rooms[i].roomName = word;//It gives "Index out of range exception" error.
}
}
You're getting an error because, while you have created a new hotel, you haven't added any rooms to it. Your code would have to do something like the following:
for (int i = 0; i < h.Length; i++)
{
h[i] = new hotel();
h[i].rooms.Add(new room { roomName = word });
}
If you want to add multiple rooms, you would either need to call Add multiple times or do so inside of an inner loop:
for (int i = 0; i < h.Length; i++)
{
h[i] = new hotel();
// Add 10 rooms
for (int a = 0; a < 10; a++)
{
h[i].rooms.Add(new room { roomName = word });
}
}
You have not added a room to the hotel:
h[i] = new hotel();
var room = new room();
room.roomName = word;
h[i].rooms.Add(room);
It may be easier to have a shortcut method in your class:
public class Hotel
{
public Hotel()
{
Rooms = new List<Room>();
}
public List<Room> Rooms { get; private set; }
public string Name { get; private set; }
public Hotel WithName(string name)
{
Name = name;
return this;
}
public Hotel AddRoom(string name)
{
Rooms.Add(new Room { Name = name });
return this;
}
}
public class Room
{
public string Name { get; set; }
}
Returning the Hotel object itself will allow method chaining on the same object to make the operations read fluently.
Demo:
var hotels = new List<Hotel>();
var hiltonHotel = new Hotel()
.WithName("Hilton")
.AddRoom("104")
.AddRoom("105");
hotels.Add(hiltonHotel);
Demo 2:
var hotelNames = new List<string> { "Hilton", "Sheraton", "Atlanta" };
var hotels = new List<Hotel>();
foreach(var hotelName in hotelNames)
{
var hotel = new Hotel()
.WithName(hotelName);
hotels.Add(hotel);
}
Demo 2 with LINQ:
var hotelNames = new List<string> { "Hilton", "Sheraton", "Atlanta" };
var hotels = hotelNames.Select(h => new Hotel().WithName(h)).ToList();
Use, You need to add room to hotel
h[i].rooms.Add(new room {roomName = word});
Instead of
h[i].rooms[i].roomName = word;
Some background of the application. This is for a WASP and SMPP transmitter accounts I have.
I have a list<> that contains an object that has all the necessary objects for a SMPP PDU and to send a message.
This list contains a property called "Routing Label" the routing label will indicate which one of the service providers to submit the PDU to (Vodacom, MTN, Cell C).
I have another list of accounts where I can bind to the SMPP server and send messages over. This list also contains the routing label and has a name for the transmitter account. So for example Vodacom's routing label is "D082" and I have two accounts that I can bind to simultaneously.
I now need to take the first List<> and update the fields. Lets say the first List<> has 1000 items. I will need to split these(more or less evenly) amongst all the accounts I have for each "Routing Label" that occurs in the second List<> mentioned.
I would prefer to achieve the desired functionality using linq or lambda.
Edited:Added code example so that you kind people may help me :-) Sorry for the poor standard but I quickly stripped some code out for you guys. I hope this helps with my problem.
static void Main(string[] args)
{
List<MobileAccounts> TransmitterAccounts = new List<MobileAccounts>();//This list contains my transmitter accounts
MobileAccounts item = new MobileAccounts();
item.FriendlyName = "Vodacom 1";
item.RoutingLabel = "D082";
TransmitterAccounts.Add(item);
MobileAccounts item1 = new MobileAccounts();
item1.FriendlyName = "Vodacom 2";
item1.RoutingLabel = "D082";
TransmitterAccounts.Add(item1);
MobileAccounts item2 = new MobileAccounts();
item2.FriendlyName = "MTN 1";
item2.RoutingLabel = "D083";
TransmitterAccounts.Add(item2);
MobileAccounts item3 = new MobileAccounts();
item3.FriendlyName = "MTN 2";
item3.RoutingLabel = "D083";
TransmitterAccounts.Add(item3);
MobileAccounts item4 = new MobileAccounts();
item4.FriendlyName = "MTN 3";
item4.RoutingLabel = "D083";
TransmitterAccounts.Add(item4);
MobileAccounts item5 = new MobileAccounts();
item5.FriendlyName = "CellC 1";
item5.RoutingLabel = "D084";
TransmitterAccounts.Add(item5);
MobileAccounts item6 = new MobileAccounts();
item6.FriendlyName = "CellC 2";
item6.RoutingLabel = "D084";
TransmitterAccounts.Add(item6);
List<SubmitSm> col = new List<SubmitSm>();//this list contains messages in a queue ready for sending
SubmitSm sitem = new SubmitSm();
sitem.DestAddr = "0722222222";//Vodacom number
sitem.RoutingLabel = "D082";
col.Add(sitem);
SubmitSm sitem1 = new SubmitSm();
sitem1.DestAddr = "0722222220";//Vodacom number
sitem1.RoutingLabel = "D082";
col.Add(sitem1);
SubmitSm sitem2 = new SubmitSm();
sitem2.DestAddr = "0722221212";//Vodacom number
sitem2.RoutingLabel = "D082";
col.Add(sitem2);
SubmitSm sitem3 = new SubmitSm();
sitem3.DestAddr = "0830000000";//MTN number
sitem3.RoutingLabel = "D083";
col.Add(sitem3);
SubmitSm sitem4 = new SubmitSm();
sitem4.DestAddr = "0833746005";//MTN number
sitem4.RoutingLabel = "D083";
col.Add(sitem4);
SubmitSm sitem5 = new SubmitSm();
sitem5.DestAddr = "0749999998";//CellC number
sitem5.RoutingLabel = "D084";
col.Add(sitem5);
/*
* Now this is where I will need
* to split all the messages in "col"
* amongst all the transmitter accounts
* I have.
*/
}
public class MobileAccounts
{
/*Please note not all items
are in this class. I have
* removed some as they are not
* neccessary for this demo code.
*/
//[DataMember]
public string FriendlyName;
//[DataMember]
public string BindName;
//[DataMember]
public string BindPassword;
//[DataMember]
public string BindHost;
//[DataMember]
public string BindPort;
//[DataMember]
public string BindType;
//[DataMember]
public string ProviderCode;
//[DataMember]
public string RoutingLabel;
}
public class SubmitSm
{
/*Please note not all items
are in this class. I have
* removed some as they are not
* neccessary for this demo code.
*/
public byte DefaultMessageId { get; set; }
public string DestAddr { get; set; }
public byte DestAddrNpi { get; set; }
public byte DestAddrTon { get; set; }
public string MessageText { get; set; }
public byte PriorityFlag { get; set; }
public byte ProtocolId { get; set; }
public byte RegisteredDelivery { get; set; }
public string ScheduleDeliveryTime { get; set; }
public string ServiceType { get; set; }
public string SourceAddr { get; set; }
public byte SourceAddrNpi { get; set; }
public byte SourceAddrTon { get; set; }
public string ValidityPeriod { get; set; }
public string RoutingLabel { get; set; }
}
Thank you to all who have contributed. #NinjaNye your solution is close but does not exactly fit my requirements. I do appreciate your effort though.
I think I am almost there but I am struggling. Can someone, anyone please help me figure out the sub select shown below:
List<IGrouping<string, MobileAccounts>> sad1 = TransmitterAccounts.GroupBy(y => y.RoutingLabel).ToList();
col = (List<SubmitSm>)col.Select
(x =>
{
x.ServiceType = sad1.Where
(z =>
z.Key== x.ServiceType
)
.Select
(y =>
new
{
//this should return the Transmitter account that has the lowest count
TransmitterAccount = y.OrderBy(ui => x.ServiceType.Count()).Select(ui => ui.FriendlyName).First()
}
).First().TransmitterAccount;
return x;
}
).ToList();
The only use of Linq I can see here would be the use of .Skip() and .Take() however I have created an extension method to tidy things up a bit. This will mean you can simply write the following to split any IEnumerable.
// In your example above you need to replace `items` with your `col` variable
var result = items.Split(transmitter.Count());
The extension method
http://www.ninjanye.co.uk/2013/07/splitting-distributing-list-objects.html
http://jnye.co/Posts/10/evenly-splitting-distributing-a-list-of-objects-using-linq-and-extension-methods
public static class EnumerableExtensions
{
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> source, int groups)
{
var listedSource = source.ToList();
int extra;
int groupSize = Math.DivRem(listedSource.Count(), groups, out extra);
while (listedSource.Any())
{
int newSize = groupSize;
if (extra > 0)
{
newSize++;
extra--;
}
yield return listedSource.Take(newSize);
listedSource = listedSource.Skip(newSize).ToList();
}
}
}
The result
I set this up as a quick command program to test
Here are some results so you can see how items are split:
Initial post (now refactored above)
Something like this should do it... however I have simplified the example
// This is your transmitter count
int groups = 4;
// These are your SMS's
List<int> values = new List<int>(){1,2,3,4,5,6,7,8,9};
//Calculate group size
int extra;
int groupSize = Math.DivRem(values.Count, groups, out extra);
var result = new List<IEnumerable<int>>();
while (values.Any())
{
int newSize = groupSize;
if (extra > 0)
{
// Account for extras
newSize++;
extra--;
}
result.Add(values.Take(newSize));
values = values.Skip(newSize).ToList();
}
return result;
you shoud avoid LINQ with side effects. But you can attach the object in the lists like that.
List<MobileAccounts> mas = new List<MobileAccounts>();
List<SubmitSm> sms = new List<SubmitSm>();
var result = mas.Select(ma => new {Sm=(sms.First(sm => sm.RoutingLabel == ma.RoutingLabel)),Ma=ma});
foreach (var r in result)
{
//update Properties here
}
This is a follow up question from another post but that post was answered. I have a for loop that I want to add three items to a generic class and I'm not sure how to do that. How do I add those items?
private static void TestResults()
{
List<Record> Records = new List<Record>();
for (int i = 0; i < ProxyList.Count; i++)
{
string[] split = List[i].Split('|');
// This is what i dont know how to do
// split[0] = Name, split[1] = SomeValue and split[3] = OrderNr
}
}
class Records
{
public static string Name { get; set; }
public static int SomeValue { get; set; }
public static int OrderNr { get; set; }
}
The first step is to associate the fields with instances of Records vs. the type itself. This is done by removing the static modifier
class Records
{
public string Name { get; set; }
public int SomeValue { get; set; }
public int OrderNr { get; set; }
}
To actually create instances try the following
for (int i = 0; i < ProxyList.Count; i++) {
string[] split = List[i].Split('|');
Records record = new Records() {
Name = split[0]
SomeValue = Int32.Parse(split[1])
OrderNr = Int32.Parse(split[2])
};
Records.add(record);
}
This particular example uses an object initializer to combine the acts of creating the object and settings its fields. This could be expanded into the longer form as follows
for (int i = 0; i < ProxyList.Count; i++) {
string[] split = List[i].Split('|');
Records record = new Records();
record.Name = split[0];
record.SomeValue = Int32.Parse(split[1]);
record.OrderNr = Int32.Parse(split[2]);
Records.add(record);
}
The Int32.Parse method will throw an exception if the item in the original string wasn't a number. If this is a possibility (think bad input) then you'll want to wrap the creation of Records with a try / catch statement
Well for one thing, your properties must not be static. You want different data for each instance, right? So they need to be instance properties. Personally I'd also make the type immutable, but that's another matter:
class Record // Changed from Records; each object is only a single record...
{
public string Name { get; set; }
public int SomeValue { get; set; }
public int OrderNumber { get; set; }
}
private static List<Record> ConvertRecords(IEnumerable<string> lines)
{
List<Record> records = new List<Record>();
foreach (string line in lines)
{
string[] split = line.Split('|');
Record record = new Record {
Name = split[0],
SomeValue = int.Parse(split[1]),
OrderNumber = int.Parse(split[2]);
};
records.Add(record);
}
}
As of C# 3 / .NET 3.5, a more idiomatic approach would be to use LINQ:
private static List<Record> ConvertRecords(IEnumerable<string> lines)
{
return (from line in lines
let split = line.Split('|')
select new Record {
Name = split[0],
SomeValue = int.Parse(split[1]),
OrderNumber = int.Parse(split[2]);
}).ToList();
}
}
... on the other hand, that's relatively advanced if you're really just starting to learn the language.
To be honest, Stack Overflow is better for asking specific questions than structured learning - I suggest you get hold of a good book, such as C# 4 in a Nutshell.
I'm not sure why you use static !!! but try this :
private static void TestResults()
{
List<Record> Records = new List<Record>();
for (int i = 0; i < ProxyList.Count; i++)
{;
string[] split = List[i].Split('|');
Records.Add(new Record() {Name = Namesplit[0] , SomeValue = split[1], OrderNr = split[3]}) ;
}
}
public class Response
{
public User[] Users { get; set; }
}
public class User
{
public string Uid { get; set; }
public string First_Name { get; set; }
public string Last_Name { get; set; }
public int Online { get; set; }
public int[] Lists { get; set; }
}
private void c_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
lock (this)
{
string json = e.Result;
// var response = JsonConvert.DeserializeObject(json);
var response = JObject.Parse(json);
// var COUNT = JsonConvert.DeserializeObject<List<User>>(json);
// MessageBox.Show(response.ToString());
var getcount = response["response"].Children<JObject>();
int count_friends=getcount.Cast<JToken>().Values("uid").Count();
Response rr = new Response();
for (int i = 0; i <count_friends; i++) {
//rr.Users.ToDictionary(rr.Users[i].Uid => response["response"][i]["uid"].ToString());
// rr.Users[i].First_Name = response["response"][i]["first_name"].ToString(); --DOESN'T WORKS
// Debug.WriteLine("OUT: "+(string)response["response"][i]["uid"].ToString());
//Debug.WriteLine("OUT: " + COUNT.Count());
}
Debug.WriteLine(rr.Users.ToString());
// string[] names = rr.Users.Select(d => d.First_Name).ToArray();
// string[] uids = response.Users.Select(d => d.Uid).ToArray();
// Dictionary<string,string> users = response.Users.ToDictionary(d => d.First_Name);
// Dictionary<string, string> usersById = response.Users.ToDictionary(d => d.Uid, d => d.First_Name);
}
}
I need to get acces to a dictionary like "select from Response.User all where Online==1"
But in the start how I can create a DB(linq) with classes above ?
All values stored in response["response"][i]["uid"],response["response"][i]["first_name"]...
is this what your looking for?
Dictionary<string,List<Dictionary<string,object>>>
this is vary bad design, try and rethink the problem to come up with a better solution
public struct User {
public int Uid;
public string First_Name;
public string Last_Name;
public bool isonline;
}
Than you can write values like
User[] usr= new User[count_friends];
// Response rr = new Response();
for (int i = 0; i <count_friends; i++) {
usr[i].Uid =(int) response["response"][i]["uid"];