How to Combine Two GUID Values
Asked Answered
G

12

12

I want to combine two guid values and generate a 32 bit alphanumberic value(It can be done by using hashing).

Gebler answered 5/9, 2009 at 10:54 Comment(6)
what's the purpose or reason for doing this?Article
why do you need to "combine" two guids?Article
i have two gudi input values from these two values i want to generate single guid value,which can be 16bit or 32 bit alphanumeric value.These is used for generating url for user as per my client.Gebler
but no matter how you "combine" two guids, there's no more uniqueness guarantee - unless you just string them together GUID1.ToString()+GUID2.ToString()Article
Paul's solution is what you're looking for. He hashes 2 guid byte arrays together. (A Guid is a 16-byte array, not 16-bit like your question) The result is a new guid which is a hash of the previous 2.Amylaceous
It doesn't have to be about uniqueness. I combine two GUIDs to simplify my data structures. The first one is a public receiver ID, the second one is a private session ID of sender. To prevent unauthorized senders (without valid session ID) from sending data to arbitrary receivers of their choice, I'm using combined GUIDs as keys in routing tables on the server.Hardie
M
18

Not Pretty, but it works..

 private static Guid MungeTwoGuids(Guid guid1, Guid guid2)
 {
     const int BYTECOUNT = 16;
     byte[] destByte = new byte[BYTECOUNT];
     byte[] guid1Byte = guid1.ToByteArray();
     byte[] guid2Byte = guid2.ToByteArray();
     
     for (int i = 0; i < BYTECOUNT; i++)
     {
         destByte[i] = (byte) (guid1Byte[i] ^ guid2Byte[i]);
     }
      return new Guid(destByte);
 }

and yes, I can deal with the non-unique-guarantee in my case

Marlomarlon answered 29/10, 2009 at 1:36 Comment(0)
B
7

What about splitting the Guids into 2 chunks of 8 bytes each, convert them to ulong (8 bytes), XOR combine them and then concat the 2 results.

public static Guid Combine(this Guid x, Guid y)
        {
            byte[] a = x.ToByteArray();
            byte[] b = y.ToByteArray();

            return new Guid(BitConverter.GetBytes(BitConverter.ToUInt64(a, 0) ^ BitConverter.ToUInt64(b, 8))
                .Concat(BitConverter.GetBytes(BitConverter.ToUInt64(a, 8) ^ BitConverter.ToUInt64(b, 0))).ToArray());
        }
Blackmore answered 24/3, 2011 at 9:12 Comment(1)
It's important to notice that A XOR B is not equal to B XOR A in the suggested implementationDismissive
B
3

You can't convert 2 128-bit GUIDs into a 16-bit or 32-bit value and maintain uniqueness. For your stated application (use value in URL) this doesn't seem to make sense, as a given value in the URL could map to any number of GUID combinations. Have you considered this?

The best approach would be to use an URL-shortening lookup where you generate a unique ID and map it to the GUIDs if needed - similarly to bit.ly or tinyurl.com.

Brandebrandea answered 5/9, 2009 at 11:12 Comment(2)
And why is uniqueness not maintened? It's still 'unique' in the sense that there's only one Guid represented by that 128-bit sequence.Robey
@RamziHammouda because when you shrink something from 128 bits to 16 or 32 bits, you lose information. So multiple different 128-bit GUIDs could map to a single 16- or 32-bit value after conversion.Brandebrandea
B
3

I actually did have a need to merge two Guids together to create a third Guid. Where the third Guid (not necessarily unique) would be the same regardless of the order the two original Guids were supplied. So I came up with this:

public static Guid Merge(Guid guidA, Guid guidB)
{
    var aba = guidA.ToByteArray();
    var bba = guidB.ToByteArray();
    var cba = new byte[aba.Length];

    for (var ix = 0; ix < cba.Length; ix++)
    {
        cba[ix] = (byte)(aba[ix] ^ bba[ix]);
    }

    return new Guid(cba);
}
Bodycheck answered 7/4, 2018 at 23:14 Comment(0)
W
3
var a = Guid.NewGuid();
var b = Guid.NewGuid();
var hashOfXor = Xor(a, b).GetHashCode();


public static Guid Xor(Guid a, Guid b)
{
    unsafe
    {
        Int64* ap = (Int64*) &a;
        Int64* bp = (Int64*) &b;
        ap[0] ^= bp[0];
        ap[1] ^= bp[1];

        return *(Guid*) ap;
    }
}
Wakayama answered 3/9, 2018 at 6:53 Comment(3)
This is just sad, answer has no GC calls, no loops, uses the CPU cache pipeline as good as one can possibly hope. Gets 0 upvotes. It's just wrong.Harrelson
probably because there isn't any explanation alongside the codeHylophagous
Yep, and having to "unsafe" your project for merging 2 guids can be useful when you search for performance, but when its not critical, the other solution is more friendlyWb
S
2

Assuming you want to generate a 32 byte value you can just concatenate the GUIDs since they are 16 byte each. If you really need a 32 bit value the only solution I see is generating your own 32 bit values and storing the related GUIDs in a database so you can retrieve them later.

Sunburn answered 5/9, 2009 at 11:26 Comment(0)
F
1

Depends on the platform and details of what you are trying to do.

In .NET/C# you could jus take avery simple approach:

var result = g1.GetHashCode() ^ g2.GetHashCode();
Ferricyanide answered 5/9, 2009 at 11:8 Comment(0)
L
1

In .NET Core 3 we can use Sse2/Span<T> to speed things up, and avoid all allocations. Essentially this code treats a Guid as 2 consecutive Int64 values, and performs the xor on them. SSE2 performs the xor in a single processor instruction (SIMD).

public static Guid Xor(this Guid a, Guid b)
{
    if (Sse2.IsSupported)
    {
        var result = Sse2.Xor(Unsafe.As<Guid, Vector128<long>>(ref a), Unsafe.As<Guid, Vector128<long>>(ref b));
        return Unsafe.As<Vector128<long>, Guid>(ref result);
    }

    var spanA = MemoryMarshal.CreateSpan(ref Unsafe.As<Guid, long>(ref a), 2);
    var spanB = MemoryMarshal.CreateSpan(ref Unsafe.As<Guid, long>(ref b), 2);

    spanB[0] ^= spanA[0];
    spanB[1] ^= spanA[1];

    return b;
}
Loner answered 3/9, 2020 at 7:45 Comment(0)
B
1

I would use an UUID5 (name-based) to combine two GUIDs, see https://mcmap.net/q/22029/-how-to-create-deterministic-guids

Guid g1 = new Guid("6164742b-e171-471b-ad6f-f98a78c5557e");
Guid g2 = new Guid("acbc41aa-971c-422a-bd42-bbcefa32ffb4");

Guid g12 = Create(IsoOidNamespace, g1.ToString() + g2.ToString(), 5)

In this example g12 would be: e1ccaee5-ea5e-55c6-89a5-fac02043326e.

There's no native support in the .NET Framework for creating these, but the code is posted on GitHub that implements the algorithm.

See as well the following .NET Fiddle, https://dotnetfiddle.net/VgHLtz

Basanite answered 3/6, 2022 at 8:53 Comment(0)
P
0

Why not try a simple operator i.e. AND, OR, XOR etc. To combine the two. XOR would be your best bet hear I would imagine as it has the nice property of when xoring the result with either of the two inputs you will get the other.

Edit: having just looked at this solution, there is a problem with it. The values would have to be normalised. Take a look at Vinay's Answer for a better solution.

Plutus answered 5/9, 2009 at 11:10 Comment(0)
M
0

Here's a one-liner for you:

g1.ToByteArray().Concat(g2.ToByteArray()).GetHashCode()
Marvamarve answered 29/1, 2014 at 19:28 Comment(0)
H
0
public static string Merge(Guid one, Guid two)
    {
        return new List<Guid>() { one, two }
            .OrderBy(x => x.GetHashCode())
            .Select(y => y.ToString().ToLowerInvariant())
            .Aggregate((a, b) => ${a.ToLowerInvariant()}_{b.ToLowerInvariant()}");
    }

So in my situation i needed to maintain order in order to make sure that the 2 Guids could be merged regardless of order. Therefore they have to be ordered. That was step one. Then, it's simply selecting the guids to string and for consitency (super important), I used string.ToLowerInvariant(). Then concatenated them using the .Aggregate function.

Haught answered 24/6, 2019 at 21:49 Comment(3)
Could you add a bit of explanation or comment for your code?Membranophone
Yeah, so in my situation i needed to maintain order in order to make sure that the 2 Guids could be merged regardless of order. Therefore they have to be ordered. That was step one. Then, it's simply selecting the guids to string and for consitency (super important), I used string.ToLowerInvariant(). Then concatenated them using the .Aggregate function.Haught
Thanks for the reply. I meant to edit your answer to include the comment, instead of having just a block of code, so that it's easier for the future visitors to understand.Membranophone

© 2022 - 2024 — McMap. All rights reserved.