Ksdmg Ksdmg - 17 days ago 69
Vb.net Question

How to find a match in a list of LxWxT where Positions of L and W can vary

I have been given the following Problem: We need to find out if a given combination of Length, Width and Thickness might have a rawmaterial on stock.
As Input I get the following String:


"L:90 W:40 T:8"


For Rawmaterials I have created a small dataclass:

Public Class RawMatInfo

Private _length As String
Private _width As String
Private _thickness As String

Public Property Length As String
Get
Return Me._length
End Get
Set(value As String)
Me._length = value
End Set
End Property

Public Property Width As String
Get
Return Me._width
End Get
Set(value As String)
Me._width = value
End Set
End Property

Public Property Thickness As String
Get
Return Me._thickness
End Get
Set(value As String)
Me._thickness = value
End Set
End Property
End Class


Here is some Sample raw material data:

Dim RawMatInfo As New List(Of RawMatInfo) From {
New RawMatInfo With {
.Length = "0",
.Width = "20",
.Thickness = "3"},
New RawMatInfo With {
.Length = "0",
.Width = "20",
.Thickness = "8"},
New RawMatInfo With {
.Length = "0",
.Width = "90",
.Thickness = "8"},
New RawMatInfo With {
.Length = "0",
.Width = "100",
.Thickness = "8"},
New RawMatInfo With {
.Length = "0",
.Width = "120",
.Thickness = "8"},
New RawMatInfo With {
.Length = "0",
.Width = "140",
.Thickness = "8"},
New RawMatInfo With {
.Length = "260",
.Width = "190",
.Thickness = "3"}
}


I have used 0 in length as wildcard because the raw material has theoretically infinite length. Because Length and Width are exchangable, the result for "L:90 W:40 T:8" has to be

RawMatInfo With {
.Length = "0",
.Width = "90",
.Thickness = "8"}


So how do I get the right Rawmaterial out of the collection if one exists? I Tried several LINQ ways, but they all appeared MUCH to complicated. Here is one I tried:

Public Function GetRawMaterial(ByVal description As String) As RawMatInfo

Dim tmpString = Split(description)
Dim DescriptionDict As New Dictionary(Of String, String)

For Each KVP In tmpString
If InStr(KVP, ":") > 0 Then
Dim tmpKVP = Split(KVP, ":")
DescriptionDict.Add(tmpKVP(0), tmpKVP(1))
End If
Next

If DescriptionDict.ContainsKey("T") Then
If DescriptionDict.ContainsKey("W") Then
If DescriptionDict.ContainsKey("L") Then

Dim RawMat = RawMatInfo.Where(Function(x) x.Thickness = DescriptionDict("T"))
If RawMat.Count > 0 Then
RawMat = RawMat.Where(Function(x) x.Width = DescriptionDict("W") Or x.Length = DescriptionDict("W") Or x.Length = "0")
If RawMat.Count > 0 Then
RawMat = RawMat.Where(Function(x) x.Width = DescriptionDict("L") Or x.Length = DescriptionDict("L"))
If RawMat.Count > 0 Then
Return RawMat
End If
End If
End If
End If
End If
End If

Return Nothing
End Function


I Hope someone can help me to find an efficient way of doing this and loosen the knob in my brain

Answer Source

Just because you input is a string don't use string for lengths, lengths are not strings they are numbers and your class should reflect that, its a model of something.

Also if you want to compare to instance of the same class the logic usually goes into that class or an implementation on IEqualtyComparer.

My vb is too rusty but in C# it would look like this.

public class RawMatInfo : IEquatable<RawMatInfo>
{
    public RawMatInfo(decimal length, decimal width, decimal thickness)
    {
        Length = length;
        Width = width;
        Thickness = thickness;
    }

    public RawMatInfo(string input)
    {
        var values = input.Split(' ').ToDictionary(x => 
            x.Split(':').First(), x => x.Split(':').Last());
        Length = Convert.ToDecimal(values["L"]);
        Width = Convert.ToDecimal(values["W"]);
        Thickness = Convert.ToDecimal(values["T"]);
    }

    public decimal Length { get; }

    public decimal Width { get; }

    public decimal Thickness { get; }

    public bool Equals(RawMatInfo other)
    {
        if(other == null) return false;
        return Length == other.Length 
            && Width == other.Width
            && Thickness == other.Thickness;
    }
}

Then you can just make a list and see if it is in there:

var list = new List<RawMatInfo>
{
    new RawMatInfo(90, 40, 8),
    new RawMatInfo(100, 40, 8),
    new RawMatInfo(90, 40, 10),
};  

var search = new RawMatInfo("L:90 W:40 T:8");
var match = list.FirstOrDefault(i => i.Equals(search));