Dmitrii Mikhailov
Dmitrii Mikhailov

Reputation: 5241

Join two dictionaries by value diffs

I have these two dictionaries:

Dictionary<char, double> analyzed_symbols = new Dictionary<char, double>();
Dictionary<char, double> decode_symbols = new Dictionary<char, double>();

I need to create another dictionary that should have their keys as key and value, like this:

Dictionary<char, char> replace_symbols = new Dictionary<char, char>();

The condition to "join" them is that difference between values should be minimal, like this:

Math.Min(Math.Abs(analyzed_symbols[key] - decode_symbols[key]))

I guess I should use LINQ for this purpose but can't figure out how to write query properly.

Data Sample:

analyzed_symbols = [a, 173], [b, 1522], [z, 99]
decode_symbols = [в, 100], [д, 185], [e, 1622]

For these dicts output data should look like this:

replace_symbols = [z, в], [b, е], [a, д]

I've found question that is pretty close to what I need, but not exactly. Snowy asks there about one close value, but I need to do the same thing for two dictionaries.

Upvotes: 1

Views: 140

Answers (3)

Magnus
Magnus

Reputation: 47036

This is my take on it:

var analyzed_symbols = new Dictionary<char, double>(){ {'a', 173}, {'b', 1522}, {'z', 99} };
var decode_symbols = new Dictionary<char, double>(){ {'в', 100}, {'д', 185}, {'e', 1622} };

var q = from a in analyzed_symbols
        from d in decode_symbols
        let tmp = new { A = a.Key, D = d.Key, Value = Math.Abs(a.Value - d.Value) }
        group tmp by tmp.A into g
        select new
        {
            Key = g.Key,
            Value = g.OrderBy (x => x.Value).Select (x => x.D).First()
        };

var replace_symbols = q.ToDictionary (x => x.Key, x => x.Value);

Upvotes: 1

Scott Chamberlain
Scott Chamberlain

Reputation: 127603

I am not exactly sure how to do it via LINQ but here is the longhand version of what you want to do.

private static Dictionary<char, char> BuildReplacementDictionary(Dictionary<char, double> analyzedSymbols,
                                                                 Dictionary<char, double> decodeSymbols)
{
    Dictionary<char, char> replaceSymbols = new Dictionary<char, char>(analyzedSymbols.Count);

    foreach (KeyValuePair<char, double> analyzedKvp in analyzedSymbols)
    {
        double bestMatchValue = double.MaxValue;

        foreach (KeyValuePair<char, double> decodeKvp in decodeSymbols)
        {
            var testValue = Math.Abs(analyzedKvp.Value - decodeKvp.Value);
            if (testValue <= bestMatchValue)
            {
                bestMatchValue = testValue;
                replaceSymbols[analyzedKvp.Key] = decodeKvp.Key;
            }
        }
    }
    return replaceSymbols;
}

What it does is it goes through each element of the analyzed dictionary, test every element of the decoded dictionary, and if that match is the same or better than the previous match it found it will use the new value from the decoded dictionary.

Upvotes: 0

IDeveloper
IDeveloper

Reputation: 1299

Okay, I'll try. I divided into several queries, because it's more readable that way.

//sorting values of the dictionaries to easily get closest
var analyzedSortedValues = analyzed_symbols.Values.OrderBy(k => k);
var decodeSortedValues = decode_symbols.Values.OrderBy(k => k);

//creating pairs of the closest values. Here I use iterator index i to skip
//some values that have been used already (is it correct?)
var t = analyzedSortedValues.Select((k, i) => new { a = k, d = decodeSortedValues.Skip(i).Any() ? decodeSortedValues.Skip(i).First() : -1 });

//printing results by getting appropriate keys from corresponding dictionaries       
foreach (var item in t)
{
    Console.WriteLine("[{0}, {1}]", analyzed_symbols.FirstOrDefault(kvp => kvp.Value == item.a).Key, decode_symbols.FirstOrDefault(kvp => kvp.Value == item.d).Key);
}

Upvotes: 0

Related Questions