How to merge two dictionaries in C# with duplicates - c#-3.0

Is there a way in C# to merge two dictionaries? I have two dictionaries that may has the same keys, but I am looking for a way to merge them so, in the end there is a dictionary with one key and the values from both the dictionaries merged.
I found the following code but it does not handle duplicates.
Dictionary Mydictionary<string, string[]> = new Dictionary<string, string[]>();
Mydictonary.Union(secondDictionary).ToDictionary( pair => pair.Key, pair => pair.Value);

If you want a LINQ approach, try this:
Dictionary<string, string[]> firstDic = new Dictionary<string, string[]>
{
{"apple", new [] {"red"}},
{"orange", new [] {"orange"}}
};
Dictionary<string, string[]> secondDic = new Dictionary<string, string[]>
{
{"apple", new [] {"green"}},
{"banana", new [] {"yellow"}}
};
Dictionary<string, string[]> resultDic = firstDic.Union(secondDic)
.GroupBy(o => o.Key)
.ToDictionary(o => o.Key, o => o.SelectMany(kvp => kvp.Value).ToArray());
For the sample data, you'll get a Dictionary with 3 KeyValuePairs, and the item with a Key of "apple" will have an Array with "red" and "green" for the value.

Maybe something like this:
foreach (var value in secondDictionary)
if (myDictionary.Contains(value.Key))
myDictionary[value.Key] = myDictionary[value.Key]
.Concat(value.Value).ToArray();
else
myDictionary[value.Key] = value.Value;

This should do it:
Dictionary<string, string[]> dict1 = new Dictionary<string, string[]>();
Dictionary<string, string[]> dict2 = new Dictionary<string, string[]>();
Dictionary<string, List<string>> combined = new Dictionary<string, List<string>>();
foreach (var pair in dict1) combined.Add(pair.Key, new List<string>(pair.Value));
foreach (var pair in dict2)
{
List<string> list;
if (!combined.TryGetValue(pair.Key, out list)) combined.Add(pair.Key, list = new List<string>());
list.AddRange(pair.Value);
}
If you really want the result as a Dictionary<string, string[]>, you can tack this on to the end:
Dictionary<string, string[]> combinedArray = new Dictionary<string, string[]>();
foreach (var pair in combined) combinedArray.Add(pair.Key, pair.Value.ToArray());

Related

getting array from object from api and diplay iteratively

I am getting an array of object json encoded from an api and i would like to display an the each row of objects on a new line
var me3 = jsondata["message"];
for (var i = 1; i < me3.length; i++)
me3.forEach((element) => print(element));
Set<String> set = Set.from(me3);
set.forEach((element) => premiumList
..add(Property(propertyName:"Company : $element[1]", propertyLocation:"SSN : 3001245" )));
The aim is to display each record on a new property sheet and display the the tradename value in each row ..
Using StringBuffer we print
var responseFromAPI = ["test1", "test2", "test3", "test4"];
String _errorMessage = "";
StringBuffer sb = new StringBuffer();
for (String line in responseFromAPI) {
sb.write(line + "\n");
}
_errorMessage = sb.toString();
print(_errorMessage);

Xamarin Essentials Unable to exchange Okta authorization code for token

I was using OpenID and we have to switch to Xamarin.Essentials.WebAuthenticator.
I can get an authorization code from Okta using WebAuthenticator.AuthenticateAsync().
But, everything I try to then translate that code into an access token returns 400 Bad Request.
Okta's API error is "E0000021: HTTP media type not supported exception" and it goes on to say, "Bad request. Accept and/or Content-Type headers likely do not match supported values."
I have tried to follow https://developer.okta.com/blog/2020/07/31/xamarin-essentials-webauthenticator as much as possible, but we are not using the hybrid grant type like he is.
We are using only Authorization Code, which means I have to make a secondary call, and I have spent two days trying to figure out how.
private async Task LoginOktaAsync()
{
try
{
var loginUrl = new Uri(BuildAuthenticationUrl()); // that method is down below
var callbackUrl = new Uri("com.oktapreview.dev-999999:/callback"); // it's not really 999999
var authenticationResult = await Xamarin.Essentials.WebAuthenticator.AuthenticateAsync(loginUrl, callbackUrl);
string authCode;
authenticationResult.Properties.TryGetValue("code",out authCode);
// Everything works fine up to this point. I get the authorization code.
var url = $"https://dev-999999.oktapreview.com/oauth2/default/v1/token"
+"?grant_type=authorization_code"
+$"&code={authCode}&client_id={OktaConfiguration.ClientId}&code_verifier={codeVerifier}";
var request = new HttpRequestMessage(HttpMethod.Post, url);
var client = new HttpClient();
var response = await client.SendAsync(request); // this generates the 400 error.
}
catch(Exception e)
{
Debug.WriteLine($"Error: {e.Message}");
}
}
Here are the methods that produce the login url and a couple of other things:
public string BuildAuthenticationUrl()
{
var state = CreateCryptoGuid();
var nonce = CreateCryptoGuid();
CreateCodeChallenge();
var url = $"https://dev-999999.oktapreview.com/oauth2/default/v1/authorize?response_type=code"
+ "&response_mode=fragment"
+ "&scope=openid%20profile%20email"
+ "&redirect_uri=com.oktapreview.dev-999999:/callback"
+$"&client_id={OktaConfiguration.ClientId}"
+$"&state={state}"
+$"&code_challenge={codeChallenge}"
+ "&code_challenge_method=S256"
+$"&nonce={nonce}";
return url;
}
private string CreateCryptoGuid()
{
using (var generator = RandomNumberGenerator.Create())
{
var bytes = new byte[16];
generator.GetBytes(bytes);
return new Guid(bytes).ToString("N");
}
}
private string CreateCodeChallenge()
{
codeChallenge = GenerateCodeToVerify();
codeVerifier = codeChallenge;
using (var sha256 = SHA256.Create())
{
var codeChallengeBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeChallenge));
return Convert.ToBase64String(codeChallengeBytes);
}
}
private string GenerateCodeToVerify()
{
var str = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~";
Random rnd = new Random();
for (var i = 0; i < 100; i++)
{
str += possible.Substring(rnd.Next(0,possible.Length-1),1);
}
return str;
}
'''
After much online research, I discovered the issue was with how I was doing my post to get the token. This is how I made it work:
public static Dictionary<string, string> JsonDecode(string encodedString)
{
var inputs = new Dictionary<string, string>();
var json = JValue.Parse(encodedString) as JObject;
foreach (KeyValuePair<string, JToken> kv in json)
{
if (kv.Value is JValue v)
{
if (v.Type != JTokenType.String)
inputs[kv.Key] = v.ToString();
else
inputs[kv.Key] = (string)v;
}
}
return inputs;
}
private async Task<string> ExchangeAuthCodeForToken(string authCode)
{
string accessToken = string.Empty;
List<KeyValuePair<string, string>> kvdata = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("grant_type", "authorization_code"),
new KeyValuePair<string, string>("code", authCode),
new KeyValuePair<string, string>("redirect_uri", OktaConfiguration.Callback),
new KeyValuePair<string, string>("client_id", OktaConfiguration.ClientId),
new KeyValuePair<string, string>("code_verifier", codeVerifier)
};
var content = new FormUrlEncodedContent(kvdata);
var request = new HttpRequestMessage(HttpMethod.Post, OktaConfiguration.TokenUrl)
{Content = content, Method = HttpMethod.Post};
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.SendAsync(request);
string text = await response.Content.ReadAsStringAsync();
Dictionary<string, string> data = JsonDecode(text);
data.TryGetValue("access_token", out accessToken);
return accessToken;
}

How Can I convert a Map of (Key1=Value1,Key2=Value2) into a Map of (Value1=Valu2) in Apex?

I have Map<String, Object> results = {Id=10001,Value=7777},
I want a map with {10001=7777} type.
This is what I attempted :-
Map<String,String> TraversedResultMap = new Map<String,String>();
for (String s : results.KeySet()) {
TraversedResultMap.put(String.valueOf((String)results.get(s)),String.valueOf((String)results.get(s)));
}
system.debug('###TRAVERSED RESULT'+TraversedResultMap);
But I'm getting o/p as : {10001=10001,7777=7777}
You're not inserting key as a value in your for loop. That's why you're getting same key-value pair.
See below code:
Map<String,String> TraversedResultMap = new Map<String,String>();
for (String s : results.KeySet()) {
// here key: String.valueOf((String)results.get(s))
// and Value: s
TraversedResultMap.put(String.valueOf((String)results.get(s)),s);
}
system.debug('###TRAVERSED RESULT'+TraversedResultMap);

LINQ to Entity cannot use System.Object.GetValue

Below find a method that does not work. We fail on the line query.Select(...
Below that find a method with hard coded object property names which does work. But, this method is obviously not dynamic, nor flexible. There may be many properties of a Customer I may wish to search on.
The error string is at bottom. I get it that somehow the LINQ to Entity is unable to deal with conversion of GetValue to some sort of TSQL. Would anyone know of how I might code this up?
public List<Customer> GetForQuery(params Tuple<string, string>[] keyValuePairs) {
using (var db = new DBEntities()) {
var availableProperties = typeof(Customer).GetTypeInfo().DeclaredProperties.ToList();
var query = db.Customers.Select(c => c);
foreach (Tuple<string, string> pair in keyValuePairs) {
PropertyInfo pi = availableProperties.First(p => p.Name.Equals(pair.Item1));
if (pi == null)
continue;
query = query.Where(u => pi.GetValue(u, null).ToString().StartsWith(pair.Item2));
}
var results = query.Select(c => c).ToList();
return results;
}
}
How I might call the above:
CustomerController custController = new CustomerController();
List<Customer> results = custController.GetForQuery(Tuple.Create<string, string>("FName", "Bob" ));
The working fixed method:
public List<Customer> GetForQuery(string firstName = "", string lastName = "", string phoneNumber = "") {
using (var db = new DBEntities()) {
var query = db.Customers.Select(c => c);
if (firstName.HasContent())
query = query.Where(u => u.FName.StartsWith(firstName));
if (lastName.HasContent())
query = query.Where(u => u.LName.StartsWith(lastName));
if (phoneNumber.HasContent())
query = query.Where(u => u.EveningPhone.StartsWith(phoneNumber));
var results = query.Select(c => c).ToList();
return results;
}
}
ERROR:
LINQ to Entities does not recognize the method 'System.Object GetValue(System.Object, System.Object[])' method, and this method cannot be translated into a store expression.

Creating anonymous types!

I know that I can do something like this:
var test = new { FirstName = string.Empty, LastName = string.empty };
But I don't if there's is a way to do it dynamically, let's say:
var test = new {};
if (condition) {
test.Property = string.Empty;
}
Let's say I Have this:
string[] names =
{
"eder",
"quiƱones",
"quoe840629",
"3301"
};
var anonymous = new {};
foreach (string name in names) {
// Create anonymous types...
}
Any suggestions?
~ Eder QuiƱones
You can do:
var test = new { FirstName = (condition ? string.Emtpy : "other") };
If you were using c# 4 you could use a dynamic type (ExpandoObject).