Remove duplicates in list - c#

I got a list of objects(ip, domainname). and want to find the duplicates in them and remove the ones that has not got www in front of the domainname.
So if it is in the list
192.168.0.0 www.stackoverflow.com
192.168.0.1 stackoverflow.com
I want to remove stackoverflow.com.
So far this is my code I am passing my list of objects to this function:
static List<ServerBindings> removeDuplicates(List<ServerBindings> inputList)
{
Dictionary<string, string> uniqueStore = new Dictionary<string, string>();
List<ServerBindings> finalList = new List<ServerBindings>();
foreach (var currValue in inputList)
{
if (!uniqueStore.ContainsKey(currValue.DomainName))
{
uniqueStore.Add(currValue.DomainName, currValue.IPAddress);
finalList.Add(new ServerBindings { DomainName = uniqueStore.Keys.ToString(), IPAddress = uniqueStore.Values.ToString() });
}
}
return finalList;
}
I have tried linq but as I'm new to it I tried to groupby but don't know how to say "select ones where it has www in front of domain name".
EDIT:
Tested this again and seems not to work...I mean the linq query selects only the ones that have www in front and ignores the ones without....to clarify if in list we have www.test.com, test.com and test3.com the end result should be www.test.com and test3.com

var result=inputList.Where(x=>x.DomainName.StartsWith("www.")).Distinct();
if distinct doesn't do the job because the bindings are different objects you could do
var result=from x in list
where x.DomainName.StartsWith("www.")
group x by x.DomainName into domain
select new ServerBindings {
DomainName=domain.Key,
IPAddress=domain.Select (d =>d.IPAddress ).First ()
};

Something like this should do the whole thing:
serverBindings
.Select(sb => new { Normalized = sb.DomainName.StartsWith("www.") ? sb.DomainName.Substring(4) : sb.DomainName, HasLeadingWWW = sb.DomainName.StartsWith("www."), Binding = sb })
.GroupBy(sbn => sbn.Normalized)
.Select(g => g.OrderBy(sbn => sbn.HasLeadingWWW).First.Binding);
NOTE: I haven't tested it, might need some tweaking.

return inputList
.GroupBy(key=>key.IpAddress)
.Select(group => {
var domain = group.Any(g=>g.StartsWith("http://www"))
? group.First(g=>g.StartsWith("http://www"))
: group.First();
return new ServerBindings
{
DomainName = group.First
IpAddress = group.Key
};)
.ToList();

Related

Getting a amount of rows with same month with LINQ from an MVC model using dateTime, is it possible?

I have this need to know how many rows have the same month from a table and I have no idea of how to do it. I thought I'd try some LINQ but I've never used it before so I don't even know if it's possible. Please help me out!
public ActionResult returTest()
{
ViewData["RowsWithSameMonth"] = // I'm guessing I can put some LINQ here?
var returer = from s in db2.ReturerDB select s;
return View(returer.ToList());
}
The ideal would be to get, maybe a two dimensional array with the month in the first cell and the amount of rows from the db in the second?
I'd like the result to be sort of :
string[,] statistics = new string[,]
{
{"2013-11", "5"},
{"2013-12", "10"},
{"2014-01", "3"}
};
Is this doable? Or should I just query the database and do a whole lot of stuff? I'm thinking that I can solve this on my own, but it would mean a lot of ugly code. Background: self taught C# developer at IT-company with 1 years experience of ugly codesmanship and no official degree of any kind.
EDIT
var returer = from s in db2.ReturerDB select s;
var dateRange = returer.ToList();
var groupedData = dateRange.GroupBy(dateRow => dateRow.ToString())
.OrderBy(monthGroup => monthGroup.Key)
.Select(monthGroup => new
{
Month = monthGroup.Key,
MountCount = monthGroup.Count()
});
string test01 = "";
string test02 = "";
foreach (var item in groupedData)
{
test01 = item.Month.ToString();
test02 = item.MountCount.ToString();
}
In debug, test01 is "Namespace.Models.ReturerDB" and test02 is "6" as was expected, or at least wanted. What am I doing wrong?
You can do this:
var groupedData = db2.ReturerDB.GroupBy(r => new { r.Date.Year, r.Date.Month })
.Select(g => new { g.Key.Year, g.Key.Month, Count = g.Count() })
.OrderBy(x => x.Year).ThenBy(x => x.Month);
.ToList();
var result = groupedData
.ToDictionary(g => string.Format("{0}-{1:00}", g.Year, g.Month),
g => g.Count);
Which will give you
Key Value
---------------
2013-11 5
2013-12 10
2014-01 3
(Creating a dictionary is slightly easier than a two-dimensional array)
This will work against a SQL back-end like entity framework of linq-to-sql, because the expressions r.Date.Year and r.Date.Month can be translated into SQL.
with a nod to mehrandvd, here is how you'd achieve this using linq method chain approach:
var dateRange = { // your base collection with the dates};
// make sure you change MyDateField to match your won datetime field
var groupedData = dateRange
.GroupBy(dateRow => dateRow.MyDateField.ToString("yyyy-mm"))
.OrderBy(monthGroup => monthGroup.Key)
.Select(monthGroup => new
{
Month = monthGroup.Key,
MountCount = monthGroup.Count()
});
This would give you the results you required, as per the OP.
[edit] - as requested, example of how to access the newly created anonymous type:
foreach (var item in groupedData)
{
Console.WriteLine(item.Month);
Console.WriteLine(item.MountCount);
}
OR, you could return the whole caboodle as a jsonresult to your client app and iterate inside that, i.e the final line of your view would be:
return Json(groupedData, JsonRequestBehavior.AllowGet);
hope this clarifies.
What you need is grouping.
Considering you have a list of dates a solution would be this:
var dateRows = // Get from database
var monthlyRows = from dateRow in dateRows
group dateRow by dateRow.ToString("yyyy/mm") into monthGroup
orderby monthGroup.Key
select new { Month=monthGroup.Key, MountCount=monthGroup.Count };
// Your results would be a list of objects which have `Month` and `MonthCount` properties.
// {Month="2014/01", MonthCount=24}
// {Month="2014/02", MonthCount=28}

Merge values in a single List

I have a simple List<string> with colon delimited values.
Some values, however, may be the same before the colon, but different after. I need to merge these two values based on the last most value.
Example
name:john
surname:michael
gender:boy
name:pete
title:captain
would become
surname:michael
gender:boy
name:pete
title:captain
list = list.GroupBy(s => s.Split(':')[0].ToLower())
.Select(g => g.Last())
.ToList();
In general: Use a Dictionary --> you're using a List AS a dictionary.
I prefer LazyDictionarys that you can update without checking key existance but for a standard .Net Dict in pseudocode
dict = new Dictionary()
for each item in your_LIST
{
tmp = item.Split(':')
if dict.ContainsKey(tmp[0])
{
dict[tmp[0]] = tmp[1]
}
else
{
dict.Add(tmp[0],tmp[1])
}
}
ANd you have a dictionary, which is what you want, if you really want to then convet it back to a list then fine, but really you probably want this to be a dictionary 'all the way down'
It can be cone using linq
private string[] inputs = new string[]
{
"name:john",
"surname:michael",
"gender:boy",
"name:pete",
"title:captain",
};
private string[] expected = new string[]
{
"surname:michael",
"gender:boy",
"name:pete",
"title:captain",
};
private static List<string> FilterList(IEnumerable<string> src) {
return src.Select(s =>
{
var pieces = s.Split(':');
return new {Name = pieces[0], Value = pieces[1]};
}).GroupBy(m => m.Name)
.Select(g => String.Format("{0}:{1}", g.Key, g.Last().Value)).ToList();;
}
[TestMethod]
public void TestFilter() {
var actual = FilterList(inputs);
CollectionAssert.AreEquivalent(expected, actual);
}

How to get first object out from List<Object> using Linq

I have below code in c# 4.0.
//Dictionary object with Key as string and Value as List of Component type object
Dictionary<String, List<Component>> dic = new Dictionary<String, List<Component>>();
//Here I am trying to do the loping for List<Component>
foreach (List<Component> lstComp in dic.Values.ToList())
{
// Below I am trying to get first component from the lstComp object.
// Can we achieve same thing using LINQ?
// Which one will give more performance as well as good object handling?
Component depCountry = lstComp[0].ComponentValue("Dep");
}
Try:
var firstElement = lstComp.First();
You can also use FirstOrDefault() just in case lstComp does not contain any items.
http://msdn.microsoft.com/en-gb/library/bb340482(v=vs.100).aspx
Edit:
To get the Component Value:
var firstElement = lstComp.First().ComponentValue("Dep");
This would assume there is an element in lstComp. An alternative and safer way would be...
var firstOrDefault = lstComp.FirstOrDefault();
if (firstOrDefault != null)
{
var firstComponentValue = firstOrDefault.ComponentValue("Dep");
}
[0] or .First() will give you the same performance whatever happens.
But your Dictionary could contains IEnumerable<Component> instead of List<Component>, and then you cant use the [] operator. That is where the difference is huge.
So for your example, it doesn't really matters, but for this code, you have no choice to use First():
var dic = new Dictionary<String, IEnumerable<Component>>();
foreach (var components in dic.Values)
{
// you can't use [0] because components is an IEnumerable<Component>
var firstComponent = components.First(); // be aware that it will throw an exception if components is empty.
var depCountry = firstComponent.ComponentValue("Dep");
}
You also can use this:
var firstOrDefault = lstComp.FirstOrDefault();
if(firstOrDefault != null)
{
//doSmth
}
for the linq expression you can use like this :
List<int> list = new List<int>() {1,2,3 };
var result = (from l in list
select l).FirstOrDefault();
for the lambda expression you can use like this
List list = new List() { 1, 2, 3 };
int x = list.FirstOrDefault();
You can do
Component depCountry = lstComp
.Select(x => x.ComponentValue("Dep"))
.FirstOrDefault();
Alternatively if you are wanting this for the entire dictionary of values, you can even tie it back to the key
var newDictionary = dic.Select(x => new
{
Key = x.Key,
Value = x.Value.Select( y =>
{
depCountry = y.ComponentValue("Dep")
}).FirstOrDefault()
}
.Where(x => x.Value != null)
.ToDictionary(x => x.Key, x => x.Value());
This will give you a new dictionary. You can access the values
var myTest = newDictionary[key1].depCountry
Try this to get all the list at first, then your desired element (say the First in your case):
var desiredElementCompoundValueList = new List<YourType>();
dic.Values.ToList().ForEach( elem =>
{
desiredElementCompoundValue.Add(elem.ComponentValue("Dep"));
});
var x = desiredElementCompoundValueList.FirstOrDefault();
To get directly the first element value without a lot of foreach iteration and variable assignment:
var desiredCompoundValue = dic.Values.ToList().Select( elem => elem.CompoundValue("Dep")).FirstOrDefault();
See the difference between the two approaches: in the first one you get the list through a ForEach, then your element. In the second you can get your value in a straight way.
Same result, different computation ;)
There are a bunch of such methods:
.First .FirstOrDefault .Single .SingleOrDefault
Choose which suits you best.
var firstObjectsOfValues = (from d in dic select d.Value[0].ComponentValue("Dep"));
I would to it like this:
//Dictionary object with Key as string and Value as List of Component type object
Dictionary<String, List<Component>> dic = new Dictionary<String, List<Component>>();
//from each element of the dictionary select first component if any
IEnumerable<Component> components = dic.Where(kvp => kvp.Value.Any()).Select(kvp => (kvp.Value.First() as Component).ComponentValue("Dep"));
but only if it is sure that list contains only objects of Component class or children

How to Map Id in List?

Dictionary<int, string> lstSrc = new Dictionary<int, string>();
Dictionary<int, string> lstDest = new Dictionary<int, string>();
lstSrc.Add(1, "All");
lstSrc.Add(2, "Weekday");
lstSrc.Add(3, "WeekEnd");
lstDest.Add(1, "All");
lstDest.Add(2, "X1");
lstDest.Add(3, "X2");
lstDest.Add(4, "Weekday");
lstDest.Add(5, "WeekEnd");
Compare only when name matches in Source and Destination
var matchingItems = lstDest
.Where(l2 => lstSrc.Any(l1 => l1.Value.Equals(l2.Value))).ToList();
matchingItems.AddRange(lstDest.Except(matchingItems));
This query gives result as see in attached image how to get that result without using LINQ ?
How i can achieve this ?
[1]: http://i.stack.imgur.com/FLicZ.png
To get the matching items you could use a query like this:
var matchingItems = List2
.Where(l2 => List1.Any(l1 => l1.TimeGroupName.Equals(l2.TimeGroupName));
matchingItems.AddRange(List2.Except(matchingItems)));
Edited: equivalent without using Linq: (It's easy to forget how much boiler plate Linq saves you from writing!)
// Get the matching items
List<TIMEGROUPINFO> matchingItems = new List<TIMEGROUPINFO>();
foreach (TIMEGROUPINFO l1 in List1)
{
foreach (TIMEGROUPINFO l2 in List2)
{
if (l1.TimeGroupName.Equals(l2.TimeGroupName))
{
matchingItems.Add(l1);
continue;
}
}
}
// Append the items from List2 which aren't already in the list:
foreach (TIMEGROUPINFO l2 in List2)
{
bool exists = false;
foreach (TIMEGROUPINFO match in matchingItems)
{
if (match.TimeGroupName.Equals(l2.TimeGroupName))
{
// This item is already in the list.
exists = true;
break;
}
}
if (exists = false)
matchingItems.Add(l2);
}
I understand that you want to perform a query on list 2 based on list 1. Linq is very good for that.
so, if you wrote something like
//List1Element is a single element in the first list.
List1Element = List1[i];
List2.Where(l2 => l2.TimeGroupName == List1Element.TimeGroupName).ToList();
That might accomplish what I think you're trying to accomplish.
If you're trying to match the entire List1 at once, you can either iterate through all the list1 elements, or you can look into Linq Join operations

Regexp find and replace with the found value

I have UK postcodes data and I would like to sort them alphabeticaly, when I do that the result is as follows;
N10-XX
N1-XX
N2-XX
N3-XX
N4-XX
N5-XX
What I want is that as follows;
N1-XX
N2-XX
N3-XX
N4-XX
N5-XX
N10-XX
Basicaly I need to add 0 at the begining of the number if it is 1 digit. like N1 should be N01 to be able to do that, what is the regexp pattern for that?
Many thanks.
Well if you are bent on using Regex, then this should do it
var text = #"N10-XX
N1-XX
N2-XX
N3-XX
N4-XX
N5-XX";
text = Regex.Replace(text, #"^N(\d)-", "N0$1-", RegexOptions.Multiline);
that said you obviously will be altering the original data, so I am not sure if this is even applicable
If you want to sort numerically, but preserve the original data, then you may need to do something like this
text.Split('\n')
.Select(o => new { Original = o, Normal = Regex.Replace(o, #"^N(\d)-", "N0$1-", RegexOptions.Compiled)})
.OrderBy(o => o.Normal)
.Select(o => o.Original)
I'm not sure from the example which numbers in the post code need to be ordered. here is some regex examples for valid uk post codes http://blogs.creative-jar.com/post/Valid-UK-Postcdoe-formats.aspx. if you incorporate this using the method above you should be able to do it.
Here is a sort function returning original string in natural(?) order.
List<string> list1 = new List<string>{ "N10-XX","N1-XX","N2-XX","N3-XX","N4-XX","N5-XX" };
List<string> list2 = new List<string>() { "File (5).txt", "File (1).txt", "File (10).txt", "File (100).txt", "File (2).txt" };
var sortedList1 = MySort(list1).ToArray();
var sortedList2 = MySort(list2).ToArray();
public static IEnumerable<string> MySort(IEnumerable<string> list)
{
int maxLen = list.Select(s => s.Length).Max();
Func<string, char> PaddingChar = s => char.IsDigit(s[0]) ? ' ' : char.MaxValue;
return
list.Select(s =>
new
{
OrgStr = s,
SortStr = Regex.Replace(s, #"(\d+)|(\D+)", m => m.Value.PadLeft(maxLen, PaddingChar(m.Value)))
})
.OrderBy(x => x.SortStr)
.Select(x => x.OrgStr);
}

Categories