from linq projection into keyvalue pair - c#

I want from json action result to return Id and Name property from certain object, so I decided to use KeyValuePair data type.
My question is how to inject data into KeyValuePair varaible from linq projection, for example
int id = 100;
string name = "john";
var data = repository.FindById(id);
var result = new KeyValuePair<int, string>();
result = data.Where(c=>c.Name == name)
.Select(x=>.x.Id)
.Select(a=>a.Name).FirstOrDefault();

You need to Select the KeyValuePair in your query.
int id = 100;
string name = "john";
var data = repository.FindById(id);
var result = data.Where(c=>c.Name == name)
.Select(x => new KeyValuePair<int,string>(x.Id, x.Name))
.FirstOrDefault();

Explicit way - maybe better readable - would be
var kv = new KeyValuePair<int, string>
{
Key = data.Where(c => c.Name == name).Select(x =>.x.Id).FirstOrDefault(),
Value = data.Where(c => c.Name == name).Select(a => a.Name).FirstOrDefault()
};

Related

Select Statements in LINQ Efficiency

For code shown below, I'm wondering is there a more efficient way of assigning the Status and Types in the select statement? There is no relationship between the contract and the statuses/types as the contract items are coming from an API call and the statuses/types are from a local database.
The part in question is
Status = statuses.FirstOrDefault(y => y.StatusId == x.StatusId)
Type = types.FirstOrDefault(y => y.TypeId == x.TypeId)
Is there a better way of assigning these?
var statuses = this.StatusRepository.GetActiveStatuses().ToList();
var types = this.TypeRepository.GetActiveTypes().ToList();
var contracts = this.ContractApi.GetCurrentContracts().Select(x => new ContractItem {
Id = x.Id,
Name = x.Name,
Status = statuses.FirstOrDefault(y => y.StatusId == x.StatusId) ?? Status.Empty(),
Type = types.FirstOrDefault(y => y.TypeId == x.TypeId) ?? Type.Empty()
});
For better performance you should use a dictionary or lookup:
var statuses = this.StatusRepository.GetActiveStatuses().ToLookup(x => x.StatusId);
var types = this.TypeRepository.GetActiveTypes().ToLookup(x => x.TypeId);
var emptyStatus = Status.Empty();
var emptyType = Type.Empty();
var contracts = this.ContractApi.GetCurrentContracts()
.Select(x => new ContractItem {
Id = x.Id,
Name = x.Name,
Status = statuses[x.StatusId].DefaultIfEmpty(emptyStatus).First(),
Type = types[x.TypeId].DefaultIfEmpty(emptyType).First()
});
The lookup is more readable because it enables to use DefaultIfEmpty
If you know they will exist in your local database you could store them in a Dictionary like;
var statusDict = this.StatusRepository.GetActiveStatuses().ToDictionary(s => s.StatusId);
....
Status = statusDict[x.StatusId]

Merge two Lists of same type with diff values and avoid duplicates

I have two lists of same type with different key value pairs,
List1 has "isPermanent = true" and List2 has false value and also
List1 has an extra key "nextVacationDate".
Im trying to do union of these as below but im afraid I will still get the duplicates because of different values. I need to merge both lists in to one list and order by List1 first (Permanent employees first)..is there a better way to do this using LINQ?
public newList1 List1(string abcd)
{
var result = serviceMethod1(abcd);
var newList1 = new List<emp>();
if (result == null) return null;
newList.AddRange(
result.Select(x => new Model
{
firstName = x.FName,
secondName = x.SName,
address = x.Address,
employeeId = x.EmpId,
isPermanent = true,
nextVacationDate =x.VacDt,
salary = x.Bsalary
}));
return newList1;
}
public newList2 List2(string defg)
{
var result = serviceMethod2(defg);
var newList2 = new List<emp>();
if (result == null) return null;
newList.AddRange(
result.Select(x => new Model
{
firstName = x.FName,
secondName = x.SName,
address = x.Address,
employeeId = x.EmpId,
isPermanent = false,
salary = x.Bsalary
}));
return newList2;
}
private List<emp> EmployyeList(List<emp> newList1, List<emp> newList2)
{
var sortedEmpList1 = newList1.OrderBy(i => i.Fname);
var sortedEmpList2 = newList2.OrderBy(i => i.Fname);
List<MeterModel> combinedList = newList1.Union(newList2) as List<emp>;
return combinedList;
}
You can filter the 2nd list to avoid duplicates:
newList1.Union(newList2.Where(emp2 => !newList1.Any(emp1 => emp1.employeeId == emp2.employeeId)))

C# .net regex extracting a string from within a string

I have a string output that looks like this:
ID = GC5c.U.feab4bc5-8-92e-c486eaddddf8
AESKEY1 = efbf5c9db259e345c205b0da27f6fb459D
AESKEY2 = ea85af9f1e5f42ff4fe8b9f07e7dcebc68
DESKEY1 = 6388a9e1a2fc8981189f0f412ae4e8
ID = JNPa.T.71664548-82-be2-a51aadd4a6f3
AESKEY1 = 37af9242c8879414e420f46903c16adebd3
AESKEY2 = 1259a1f6f6da03cb3984a117ca617d9ff73
DESKEY1 = 9547dc08db70cb95789f3a59e5c6adebd31
How can I iterate through the ID(s) of this list and obtain the values within the string?
Open the file, iterate through each line, and put it into a Dictionary<string, string>
Dictionary<string, string> data = new Dictionary<string, string>();
using(StreamReader reader = new StreamReader("C:/YourFilePath.txt"))
{
while (reader.Peek() >= 0)
{
string[] line = reader.ReadLine().Split('=');
data.Add(line[0].TrimEnd(), line[1].TrimStart());
}
}
UPDATE: Note that this solution is using Dictionary, and so it does not allow duplicate keys. If you need to duplicate keys, I would suggest changing this solution for a List<KeyValuePair<string, string>>. The code will get a little dirtier by the way:
List<KeyValuePair<string, string>> data = new List<KeyValuePair<string, string>>();
using(StreamReader reader = new StreamReader("C:/YourFilePath.txt"))
{
while (reader.Peek() >= 0)
{
string[] line = reader.ReadLine().Split('=');
data.Add(new KeyValuePair(line[0].TrimEnd(), line[1].TrimStart()));
}
}
I am not sure Regex is the best suited for this scenario, however, please find below a solution using it with a named group "id".
var regex = new Regex(#"id.*=\s*(?<id>.+)", RegexOptions.IgnoreCase);
var input = #"ID = Gs3c.H.feab4bc5-6c00-4ee8-9e2e-c486eaddddf8
AESKEY1 = efbf5c9db259e345c205b0da27f6fb459D
AESKEY2 = ea85af9f1e5f42ff4fe8b9f07e7dcebc68
DESKEY1 = 6388a9e1a2fc8981189f0f412ae4e8
ID = JNPa.T.71664548-82-be2-a51aadd4a6f3
AESKEY1 = 37af9242c8879414e420f46903c16adebd3
AESKEY2 = 1259a1f6f6da03cb3984a117ca617d9ff73
DESKEY1 = 9547dc08db70cb95789f3a59e5c6adebd31";
var ids = regex.Matches(input).Cast<Match>().Select(m => m.Groups["id"]);
Here is the Regex test: Regex test
NicoRiff's suggestion of using regular parsing into a Dictionary is the way to go. Here's the obligatory LINQ-based approach:
var data = File.ReadLines("C:/your/file/path.txt")
.Select(l => l.Split('='))
.ToDictionary(k => k[0], v => v[1]);
EDIT: As Nico pointed out, when the dictionary is going to contain duplicate keys, then a dictionary won't work. However, you can still use LINQ to automatically arrange the dictionary so that the ID field of your source text is the key instead of the field names. For example, you can use the following:
var data = File.ReadLines("C:/your/file/path.txt")
.Where(l => !String.IsNullOrEmpty(l))
.Select((l, i) => new { ID = i / 4, Value = l.Split('=') })
.GroupBy(x => x.ID)
.Select(g => new { ID = g.First().Value[1].Trim(), Values = g.ToDictionary(k => k.Value[0].Trim(), v => v.Value[1].Trim()) })
.ToDictionary(k => k.ID, v => v.Values);
Afterwards, you can iterate through data to get your fields:
foreach (var d in data.Values)
{
string id = d["ID"];
string aesKey1 = d["AESKEY1"];
string aesKey2 = d["AESKEY2"];
string desKey1 = d["DESKEY1"];
}
If you like to put the data into a dictionary like: Dicationary<string, Dictionary<string,string>>
Where the key of the main dictionary is the value of ID, and the internal dictionaries are the values that follows, then the following would do it:
string[] lines = input.Split('\n');
var myDict = new Dictionary<string, Dictionary<string,string>>();
var currentKey = "";
foreach (string[] keyVal in lines.Where(line=>!string.IsNullOrWhiteSpace(line))
.Select(line => line.Split('=')))
{
if (keyVal[0].StartsWith("ID"))
{
currentKey = keyVal[1].Trim();
myDict.Add(currentKey, new Dictionary<string, string>());
}
else
{
myDict[currentKey].Add(keyVal[0].Trim(), keyVal[1].Trim());
}
}
The Regex would look like so:
#"^ID\s+=\s+(.+)$"
You can test it on Regex101 and Rextester

How to Sort NameValue Collection and Store it in a string

Here I am storing two set of querystring parameters into two different namevalue collection. The querystring parameter order may vary so I just want to sort the order and then I need to store namevalue collection to a string.
Updated Code :
string url1 = #"http://www.somewebsitesampletest.com/dcs7o?data=142248494&dcp=smre&nparam=4567P&email=xxx.com";
string url2 = #"http://www.somewebsitesampletest.com/dcs7o?dcp=smre&data=142248494&email=xxx.com&nparam=4567P";
var NameValueCollection1 = HttpUtility.ParseQueryString(url1);
var NameValueCollection2 = HttpUtility.ParseQueryString(url2);
ExpectedResult:
After Sorting and converting to string the result should look like the below one
string query1 = "data=142248494&dcp=smre&email=xxx.com&nparam=4567P";
string query2 = "data=142248494&dcp=smre&email=xxx.com&nparam=4567P";
Here's a solution using Linq.
Basically it changes the NameValueCollection to an IEnumerable of the keys using Cast<T>, then the rest is fairly self explanatory.
public string GetSortedQueryString(string url)
{
var queryString = HttpUtility.ParseQueryString(url);
// Ignore null keys (caused by your ?& at the start of the query string
var orderedKeys = queryString.Cast<string>().Where(k => k != null).OrderBy(k => k);
return string.Join("&", orderedKeys.Select(k => string.Format("{0}={1}", k, queryString[k])));
}
Results for your URLs would be:
data=142248494&dcp=smre&email=xxx.com&nparam=4567P
data=142248494&dcp=smre&email=xxx.com&nparam=4567P
Email comes before nparam, unlike your expected solution (I'm assuming that was a mistake).
use LINQ with a Dictionary and a list of KeyValuePair :
string url1 = #"http://www.somewebsitesampletest.com/dcs7o?&data=142248494&dcp=smre&nparam=4567P&email=xxx.com";
string query1 ="";
Dictionary<String, String> paramDict = new Dictionary<string, string>();
var query = from match in urlString.Split('?').Where(m => m.Contains('='))
.SelectMany(pr => pr.Split('&'))
where match.Contains('=')
select new KeyValuePair<string, String>(
match.Split('=')[0],
match.Split('=')[1]);
query.ToList().ForEach(kvp => paramDict.Add(kvp.Key, kvp.Value));
var List<KeyValuePair<string, string>> paramList = paramDict.ToList();
paramList.Sort();
foreach (KeyValuePair<string, int> pair in list)
{
query1+=pair.Key+"="+pair.Value+"&";
}
query1=query1.TrimEnd('&');
I made this fiddle because I needed to sort querystring values in order to properly compare URIs: (H/T to Jacob's answer)
https://dotnetfiddle.net/eEhkNk
This preserves duplicate keys:
public static string[] QueryStringOmissions = new string[] { "b" };
public static NameValueCollection SortAndRemove(NameValueCollection collection)
{
var orderedKeys = collection.Cast<string>().Where(k => k != null).OrderBy(k => k);
var newCollection = HttpUtility.ParseQueryString(String.Empty);
foreach(var key in orderedKeys)
{
if (!QueryStringOmissions.Contains(key))
{
foreach(var val in collection.GetValues(key).Select(x => x).OrderBy(x => x).ToArray())
{
newCollection.Add(key, val);
}
}
}
return newCollection;
}

Entity Framework - getting a table's column names as a string array

If I'm using EF 5 and Database first to generate a .edmx model of my database, how do I get a list of an entity's columns?
using (var db = new ProjectNameContext())
{
// string[] colNames = db.Users.
}
What I'm looking for is colNames[0] == "Id", colNames[1] == "FirstName", etc.
How about:
var names = typeof(User).GetProperties()
.Select(property => property.Name)
.ToArray();
Of course, this can be used for any type, not just an EF table.
var res = typeof(TableName).GetProperties()
.Select(property => property.Name)
.ToArray();
OR
var res = dbContext.Model.FindEntityType(typeof(TableName))
.GetProperties().Select(x => x.Relational().ColumnName)
.ToList();
var index = 0;
var propertyInfo = res[index].PropertyInfo;
var columnName = res[index].Relational().ColumnName;
var propertyName = propertyInfo.Name;
var propertyValue = propertyInfo.GetValue(sourceObject); // NEED OBJECT TO GET VALUE

Categories

Resources