C# merge field values if the ID's match - c#

How do i match 2 objects in a list if their ID match, and their text doesn't?
my objects is added to a list:
List<MyObject> list = New List<MyObject>();
This could be my list (This is an object):
ID Text
1 this is some text
2 text1
1 more text
1 a little more
2 text 2
3 XXX
Then i would like the result to be:
ID Text
1 this is some text more text a little more
2 text1 text2
3 XXX
I've tried with a for in a for loop, but i just can figure it out..
for (int i = 0; i < OrderList.Count; i++)
{
bool existsMoreThanOnce = false;
for (int j = i; j < OrderList.Count; j++)
{
duplicates.Add(OrderList[i]);
if (OrderList[i].OrderNumber == OrderList[j].OrderNumber && OrderList[i].OrderText != OrderList[j].OrderText)
{
if(!uniques.Contains(OrderList[j]))
{
duplicates.Add(OrderList[j]);
existsMoreThanOnce = true;
}
}
}
if (existsMoreThanOnce == false)
{
uniques.Add(OrderList[i]);
}
}

First I create a class
public class Items
{
public int ID { get; set; }
public string Text { get; set; }
public Items(int id, string text)
{
ID = id;
Text = text;
}
}
Now I the logic of my code is
List<Items> objItems = new List<Items>();
objItems.Add(new Items(1,"Rahul"));
objItems.Add(new Items(2, "Rohit"));
objItems.Add(new Items(1, "Kumar"));
objItems.Add(new Items(2, "Verma"));
List<Items> objNew = new List<Items>(); //it will hold result
string str = "";
for (int i = 0; i < objItems.Count; i++)
{
if (objItems[i].ID > 0)
{
str = objItems[i].Text;
for (int j = i + 1; j < objItems.Count; j++)
{
if (objItems[i].ID == objItems[j].ID)
{
str += objItems[j].Text + " ";
objItems[j].ID = -1;
}
}
objNew.Add(new Items(objItems[i].ID, str));
}
}
ObjNew object contains the required output.

var result = list1.Concat(list2)
.GroupBy(x => x.ID)
.Where(g => g.GroupBy(x=>x.Text).Count() > 1)
.Select(x => x.Key)
.ToList();

You can start with LINQ's GroupBy.
var output = input.GroupBy(i => i.ID)
.Select(i => new { ID = i.Key,
Text = String.Join(" ",
i.Select(x => x.Text).ToArray()) });

First i created a class to hold your list
public class MyObject
{
public int ID { get; set; }
public string Text { get; set; }
}
then i inserted the dummy values into it
List<MyObject> obj = new List<MyObject>
{
new MyObject{ID=1, Text="this is some text"},
new MyObject{ID=2, Text="text1"},
new MyObject{ID=1, Text="more text"},
new MyObject{ID=1, Text="a little more"},
new MyObject{ID=2, Text="text 2"},
new MyObject{ID=3, Text="XXX"}
};
List<MyObject> obj2 = new List<MyObject>(); //this list will hold your output
//the linq query will filter out the uniques ids.
var uniqueIds = (from a in obj select new { a.ID, a.Text }).GroupBy(x => x.ID).ToList();
//then iterated through all the unique ids to merge the texts and list them under the unique ids.
int id=0;
foreach (var item in uniqueIds)
{
string contText = "";
for (int j = 0; j < item.Count(); j++)
{
contText += item.ElementAt(j).Text + " ";
id = item.ElementAt(j).ID;
}
obj2.Add(new MyObject { ID = id, Text = contText });
}
the list obj2 will have your desired output.

Related

binary search in a sorted list in c#

I am retrieving client id\ drum id from a file and storing them in a list.
then taking the client id and storing it in another list.
I need to display the client id that the user specifies (input_id) on a Datagrid.
I need to get all the occurrences of this specific id using binary search.
the file is already sorted.
I need first to find the occurrences of input_id in id_list.
The question is: how to find all the occurrences of input_id in the sorted list id_list using binary search?
using(StreamReader sr= new StreamReader(path))
{
List<string> id_list = new List<string>();
List<string> all_list= new List<string>();
List<int> indexes = new List<int>();
string line = sr.ReadLine();
line = sr.ReadLine();
while (line != null)
{
all_list.Add(line);
string[] break1 = line.Split('/');
id_list.Add(break1[0]);
line = sr.ReadLine();
}
}
string input_id = textBox1.Text;
Data in the file:
client id/drum id
-----------------
123/321
231/3213
321/213123 ...
If the requirement was to use binary search I would create a custom class with a comparer, and then find an element and loop forward/backward to get any other elements. Like:
static void Main(string[] args
{
var path = #"file path...";
// read all the Ids from the file.
var id_list = File.ReadLines(path).Select(x => new Drum
{
ClientId = x.Split('/').First(),
DrumId = x.Split('/').Last()
}).OrderBy(o => o.ClientId).ToList();
var find = new Drum { ClientId = "231" };
var index = id_list.BinarySearch(find, new DrumComparer());
if (index != -1)
{
List<Drum> matches = new List<Drum>();
matches.Add(id_list[index]);
//get previous matches
for (int i = index - 1; i > 0; i--)
{
if (id_list[i].ClientId == find.ClientId)
matches.Add(id_list[i]);
else
break;
}
//get forward matches
for (int i = index + 1; i < id_list.Count; i++)
{
if (id_list[i].ClientId == find.ClientId)
matches.Add(id_list[i]);
else
break;
}
}
}
public class Drum
{
public string DrumId { get; set; }
public string ClientId { get; set; }
}
public class DrumComparer : Comparer<Drum>
{
public override int Compare(Drum x, Drum y) =>
x.ClientId.CompareTo(y.ClientId);
}
If i understand you question right then this should be a simple where stats.
// read all the Ids from the file.
var Id_list = File.ReadLines(path).Select(x => new {
ClientId = x.Split('/').First(),
DrumId = x.Split('/').Last()
}).ToList();
var foundIds = Id_list.Where(x => x.ClientId == input_id);

Skip and take method in List

I have a class Players. And I want to create Hyperlink with Skip and Take methods. But gives me System.Linq.Enumerable error. My goal is make a pyramid user list. here is my codes
public class Players
{
public string Name{ get; set; }
public int Order{ get; set; }
public int ID { get; set; }
}
List<Players> playerlist= new List<Players>();
playerlist= (from DataRow dr in dt.Rows
select new Players()
{
Name= (dr["name"].ToString()),
Order= int.Parse(dr["order"].ToString()),
ID = int.Parse(dr["Id"].ToString())
}).ToList();
playerlist= playerlist.OrderBy(x => x.Order).ToList();
int skip = 0;
int take = 1;
int addedCount = 0;
do
{
HyperLink links= new HyperLink();
links.Text = "" + playerlist.Skip(skip ).Take(take).Select(x => x.Name);
links.NavigateUrl = "playerdetails.aspx?id=" + oyunculistesi.Skip(skip).Take(take).Select(x => x.ID);
Page.Controls.Add(links);
addedCount += take ;
skip+= take ;
take += +1;
}
while (addedCount < playerlist.Count);
It is working with StringBuilder but with HyperLink not.
sb.AppendLine(string.Join(" ", players.Skip(skip).Take(take).Select(x => $"{x.Order}) {x.Name}")));
Your Select is returning an IEnumerable of char and you need to build a string from them by using string.Join like what you did in the StringBuilder:
linkuret.Text = string.Join("" , playerlist.Skip(skip).Take(take).Select(x => x.Name));
I would rewrite your loop in this way
int skip = 0;
while (skip < playerlist.Count)
{
HyperLink links= new HyperLink();
Players p = playerlist.Skip(skip).FirstOrDefault();
links.Text = $"{p.Name}"
links.NavigateUrl = $"playerdetails.aspx?id={p.Id}"
Page.Controls.Add(links);
skip++;
}
First I have removed the Take part from your code and used FirstOrDefault to get always the first element after the skip. Finally the Players elements is loaded just one time and then I used the properties of the class with more readable code.

"Object reference not set to an instance of an object" error during the compilation

I get the "Object reference not set to an instance of an object" error when i compile the code at string[] values = lineuser.Split(' '); . Any idea?
namespace function
{
public partial class Form1 : Form
{
float userscore,itemscore,result;
string lineitem, lineuser;
//float[][] a = new float[89395][100];
//float[][] b = new float[1143600][100];
float[][] a = Enumerable.Range(0, 89395).Select(i => new float[100]).ToArray();
float[][] b = Enumerable.Range(0, 1143600).Select(j => new float[100]).ToArray();
//float[,] c = new float[89395, 100];
StreamReader fileitem = new StreamReader("c:\\ITEM_SVD_FULL.txt");
StreamReader fileuser = new StreamReader("c:\\USER_SVD_FULL.txt");
public Form1()
{
InitializeComponent();
for (int x = 0; x <= 8939500; x++)
{
lineuser = fileuser.ReadLine();
string[] values = lineuser.Split(' '); //<------the line's error
int userid, factoriduser;
foreach (string value in values)
{
userid = Convert.ToInt32(values[0]);
factoriduser = Convert.ToInt32(values[1]);
userscore = Convert.ToSingle(values[2]);
a[userid][factoriduser] = userscore;
}
}
for (int y = 0; y <= 114360000; y++)
{
lineitem = fileitem.ReadLine();
string[] valuesi = lineitem.Split(' ');
int itemid, factoriditem;
foreach (string value in valuesi)
{
itemid = Convert.ToInt32(valuesi[0]);
factoriditem = Convert.ToInt32(valuesi[1]);
itemscore = Convert.ToSingle(valuesi[2]);
b[itemid][factoriditem] = itemscore;
}
}
}
public float dotproduct(int userid,int itemid)
{
//get the score of 100 from user and item to dotproduct
float[] u_f = a[userid];
float[] i_f = b[itemid];
for (int i = 0; i <u_f.GetLength(1); i++)
{
result += u_f[userid] * i_f[itemid];
}
return result;
}
private void btn_recomm_Click(object sender, EventArgs e)
{
if(txtbx_id.Text==null)
{
MessageBox.Show("please insert user id");
}
if (txtbx_id.Text != null && txtbx_itemid==null)
{
int sc = Convert.ToInt32(txtbx_id.Text);
if (sc>=0 &&sc<=89395)
{
for (int z=0;z<=1143600;z++)
{
dotproduct(sc,z);
}
//Hashtable hashtable = new Hashtable();
//put the result in hashtable
//foreach (DictionaryEntry entry in hashtable)
//{
//Console.WriteLine("{0}, {1}", entry.Key, entry.Value);
// }
}
}
if (txtbx_id!=null &&txtbx_itemid!=null)
{
int uid = Convert.ToInt32(txtbx_id.Text);
int iid = Convert.ToInt32(txtbx_itemid.Text);
{
if (uid>=0 && uid<=89395 && iid>=0 && iid<=1143600)
{
dotproduct(uid,iid);
MessageBox.Show("The Score of user id "+uid+" is "+result);
}
}
Please check you lineuser variable is null
public Form1()
{
InitializeComponent();
for (int x = 0; x <= 8939500; x++)
{
if(!string.IsNullorEmpty(lineuser) //<--- check the string is empty
{
string[] values = lineuser.Split(' '); //<------the line's error
int userid, factoriduser;
foreach (string value in values)
{
userid = Convert.ToInt32(values[0]);
factoriduser = Convert.ToInt32(values[1]);
userscore = Convert.ToSingle(values[2]);
a[userid][factoriduser] = userscore;
}
}
}
for (int y = 0; y <= 114360000; y++)
{
lineitem = fileitem.ReadLine();
if(!string.IsNullorEmpty(lineitem) //<--- check the string is empty
{
string[] valuesi = lineitem.Split(' ');
int itemid, factoriditem;
foreach (string value in valuesi)
{
itemid = Convert.ToInt32(valuesi[0]);
factoriditem = Convert.ToInt32(valuesi[1]);
itemscore = Convert.ToSingle(valuesi[2]);
b[itemid][factoriditem] = itemscore;
}
}
}
}
Now you can avoid the error.
You haven't opened the Stream fileuser so it is still null.
It is really a bad practice to open the file while you define the global variable in your class.
But as part from this, when you call ReadLine the result could be a null because there are no more lines to read and you don't check for this case.
Looking at the code shown above, there is no need to have a global variable for the filestream, so, the usual pattern when handling resources (OPEN/USE/CLOSE) should be followed for both files
public Form1()
{
InitializeComponent();
string lineuser;
// OPEN
using(StreamReader fileuser = new StreamReader("c:\\USER_SVD_FULL.txt"))
{
// USE
while((lineuser = fileuser.ReadLine()) != null)
{
string[] values = lineuser.Split(' ');
....
}
} //CLOSE & DISPOSE
....
string lineitem;
using(StreamReader fileitem = new StreamReader("c:\\ITEM_SVD_FULL.txt"))
{
while((lineitem = fileitem.ReadLine()) != null)
{
string[] valuesi = lineitem.Split(' ');
....
}
}

Linq write new list from old list sublist, change said list, write back to old list

I'm rather new to Linq. I'm having trouble coding this.
I have a list with many different sublists.
oldList[0] some type
oldList[1] another different type
oldList[2] the type I want
oldList[3] more types
I want to select all the parameters from a specific type and write them to a temp list.
If that temp list is empty, I want to assign some values (values don't actually matter).
After changing the values, I want to write temp list back into oldList.
Please advise. This is a huge learning experience for me.
public void myFunction(list)
{
//list contains at least 5 sublists of various type
//check if the type I want is null
IEnumerable<TypeIWant> possiblyEmptyList = list.OfType<TypeIWant>(); //find the type I want from the list and save it
if (possiblyEmptyList == null) //this doesn't work and possiblyEmptyList.Count <= 1 doesn't work
{
//convert residence address to forwarding address
IEnumerable<ReplacementType> replacementList = list.OfType<ReplacementType>();
forwardingAddress = replacementList.Select(x => new TypeIWant /* this statement functions exactly the way I want it to */
{
Address1 = x.Address1,
Address2 = x.Address2,
AddressType = x.AddressType,
City = x.City,
CountryId = x.CountryId,
CountyRegion = x.CountyRegion,
Email = x.Email,
ConfirmEmail = x.ConfirmEmail,
Fax = x.Fax,
Telephone = x.Telephone,
State = x.State,
PostalCode = x.PostalCode
});
//write forwarding address back to list
//don't know how to do this
}
LINQ purpose is querying. It doesn't allow you to replace some items in collection with other items. Use simple loop instead:
IEnumerable<TypeIWant> possiblyEmptyList = list.OfType<TypeIWant>();
if (!possiblyEmptyList.Any())
{
for (int i = 0; i < list.Count; i++)
{
ReplacementType item = list[i] as ReplacementType;
if (item == null)
continue;
list[i] = ConvertToTypeIWant(item);
}
}
And conversion (which is better to do with something like automapper):
private TypeIWant ConvertToTypeIWant(ReplacementType x)
{
return new TypeIWant
{
Address1 = x.Address1,
Address2 = x.Address2,
AddressType = x.AddressType,
City = x.City,
CountryId = x.CountryId,
CountyRegion = x.CountyRegion,
Email = x.Email,
ConfirmEmail = x.ConfirmEmail,
Fax = x.Fax,
Telephone = x.Telephone,
State = x.State,
PostalCode = x.PostalCode
};
}
Not LINQ but an example.
class Program
{
static void Main(string[] args)
{
// Vars
var list = new List<List<string>>();
var a = new List<string>();
var b = new List<string>();
var c = new List<string> { "one", "two", "three" };
var d = new List<string>();
// Add Lists
list.Add(a);
list.Add(b);
list.Add(c);
list.Add(d);
// Loop through list
foreach (var x in list)
{
if (x.Count < 1)
{
var tempList = new List<string>();
tempList.Add("some value");
x.Clear();
x.AddRange(tempList);
}
}
// Print
int count = 0;
foreach (var l in list)
{
count++;
Console.Write("(List " + count + ") ");
foreach (var s in l)
{
Console.Write(s + " ");
}
Console.WriteLine("");
}
}
}
(List 1) some value
(List 2) some value
(List 3) one two three
(List 4) some value

How add only new city?

I have CreateDiscountViewByUser discountViewByUser it contains a list of cities that are chosen by the user, but they may already be those cities that have been added.
List<DiscountCity> discountCities = (from city in db.DiscountCities
where city.DiscountId == discountViewByUser.Id
select city).ToList();
for (int y = 0; y < discountCities.Count(); y++)
{
var dc = discountCities[y];
bool flag = false;
for (int i = 0; i < discountViewByUser.DiscountCitys.Length; i++)
{
if (dc.CityId == discountViewByUser.DiscountCitys[i])
{
flag = true;
discountCities.Remove(dc);
y--;
}
}
if (!flag)
{
db.DiscountCities.DeleteObject(dc);
}
}
foreach (var dc in discountCities)
{
DiscountCity discountCity = new DiscountCity
{Id = Guid.NewGuid(),
CityId = dc.CityId,
DiscountId = main.Id};
db.DiscountCities.AddObject(discountCity);
}
how to add only the new city?
My code does not work = (
UPDATE:
discountViewByUser.DiscountCitys type int[].
db.DiscountCities table: Id DiscountId CityId.
example:
in database: Odessa, Kiev
user set: Odessa, Moscow.
I need delete Kiev and add moscow how do this?
What I recommend is adding all the items and then removing duplicates.
// Where uniqueList is a List<T> of unique items:
uniqueList.AddRange(valuesToAdd);
uniqueList = uniqueList.Distinct(new CityEqualityComparer()).ToList();
// Sorry, I don't know how this would fit into your code
Since you are comparing cities by their CityId's, you will probably need to use a custom IEqualityComparer to determine which cities are duplicates.
Here is an example of such a class:
class CityEqualityComparer : IEqualityComparer<City>
{
public bool Equals(City arg1, City arg2)
{
return arg1.CityId == arg2.CityId;
}
public int GetHashCode(City arg)
{
return arg.CityId;
}
}
This question may also be of some help.
I suggest you do this in 2 steps.
1) Find the cities to be deleted
var deleteCities = db.DiscountCities.Where(c => c.DiscountId == discountViewByUser.Id
&& !discountViewByUser.DiscountCitys.Contains(c.CityId));
foreach(deleteCity in deleteCities)
{
db.DiscountCities.DeleteObject(deleteCity);
}
2) Find cityId's to be inserted
var insertCities = discountViewByUser.DiscountCitys.Except(
db.DiscountCities.Where(c => c.DiscountId == discountViewByUser.Id)
.Select(c => c.CityId));
foreach(var insertCity in insertCities)
{
DiscountCity discountCity = new DiscountCity
{Id = Guid.NewGuid(), CityId = insertCity, DiscountId = discountViewByUser.Id};
db.DiscountCities.AddObject(discountCity);
}

Categories