0

I'm having an issue in a large piece of code that I'm working on, so I created a short piece of code to show the issue. I created a class (stockstatus) that represents an inventory item . They have a part number (.part), a quantity (.qty), and a cost (.cost). I created a list (ssr) of that class to represent the entire inventory. I'm now trying to search that inventory for a specific part number, but I'm having trouble.

If I try ssr.IndexOf, it expects a stockstatus to be passed to the IndexOf function. If I create a stockstatus with an underlying .part that I initialize to the second part number ("CP0065-10N-S"), the IndexOf function always returns -1. I'm thinking that the .qty and .cost also have to match for IndexOf to return the correct index, but I have no way of knowing those values in the code that I'm working on. I need to be able to find an index based solely on searching for a .part. What is the simplest way to do this?

Public Class stockstatus
    Public part As String
    Public qty As Double
    Public cost As Double
End Class

Public Partial Class MainForm

    Public ssr As New List(Of stockstatus)

    Public Sub New()
        Me.InitializeComponent()
    End Sub

    Sub MainFormLoad(sender As Object, e As EventArgs)
        ssr = getSSR()
        Dim ss As New stockstatus
        ss.part = "CP0065-10N-S"
        MsgBox(ssr.IndexOf(ss)) 'returns -1.  i want it to return index 1
    End Sub

    Public Function getSSR() As List(Of stockstatus)
        Dim s As New List(Of stockstatus)
        Dim ss As New stockstatus
        ss.part = "CP0065-0.1U-S"
        ss.qty = 1000.0R
        ss.cost = 0.001R
        s.Add(ss)
        ss.part = "CP0065-10N-S"
        ss.qty = 2000.0R
        ss.cost = 0.002R
        s.Add(ss)
        Return s
    End Function

End Class
  • By the way... I had assumed that IndexOf would work if I specified the cost and quantity, but I tried: ss.part = "CP0065-10N-S" ss.qty = 2000.0R ss.cost = 0.002R MsgBox(ssr.IndexOf(ss)) That still returns -1, so I must be way off track. – Nicholas Reiser Dec 02 '15 at 21:41
  • Sure, cannot work, you are trying to find an object that is not in the list. You'd have to override stockstatus' Equals and GetHashCode methods so they only use the part member. Or just use a Linq expression. Or a For loop if Linq is not your cup of tea. – Hans Passant Dec 02 '15 at 21:49
  • Use a dictionary and use the part number as the key. – JerryM Dec 02 '15 at 22:00
  • The other option you have is to not use a LIST() but use something that takes a key like a hashtable or dictionary so when you add it to the list you include the key to search on. – Steve Dec 02 '15 at 22:01
  • I started the code using a dictionary, but the dictionary needed to be sorted and the underlying quantity needed to be modified dynamically. I found a way to sort the dictionary by converting it to and from a list, but I couldn't find a way to modify the quantity values dynamically. I was told to use a list. – Nicholas Reiser Dec 02 '15 at 22:03
  • 1
    If this is for a real app, an actual collection class might be better than a public collection in a form. That collection will only be available when that form is open. `Dim item = stockItems.Where(Function(x) x.PartName = "CP0065-10N-S").FirstOrDefault`. then if you really want the index: `Dim ndx = stockItems.IndexOf(item)` – Ňɏssa Pøngjǣrdenlarp Dec 02 '15 at 22:06
  • @Plutonix you have the best "hassle free" answer – Steve Dec 02 '15 at 22:12
  • I tried... ssr = getSSR() Dim item As stockstatus = ssr.Where(Function(x) x.PartName = "CP0065-10N-S").FirstOrDefault Dim ndx As Integer = ssr.IndexOf(item) MsgBox(ndx) However, this throws a compiler error that says that Where is not a member of ssr. – Nicholas Reiser Dec 02 '15 at 22:21
  • When more than one person comments, you need to use @ + name (SO will pop up a list) like @Steve did (and now me) otherwise no one will know you responded. You may need to add a ref to `System.Linq` and I used `PartName` for clarity, you'd use `part` What version of VS do you have (it is usually automatically added) – Ňɏssa Pøngjǣrdenlarp Dec 02 '15 at 22:27
  • @Plutonix thanks for the tips. I'm new to all of this. I'm supposed to be a Production Manager, but I keep finding the need to write code. Adding Imports System.Linq to the top fixed the compiler error. I changed PartName to part. It kept returning the wrong value, and I noticed that I forgot to renew the ss (stockstatus) each time I reentered it. Thanks so much!!! I'm attaching the working code as an answer in a sec. – Nicholas Reiser Dec 02 '15 at 22:36
  • you dont really need to get the index when you can get the *item* which is kind of the point of linq. Same for sorting the data...no real point when you can order it or query it however and whenever you want (BTW, *you* get pinged for new comments because they are on your post; not so us.) – Ňɏssa Pøngjǣrdenlarp Dec 02 '15 at 22:38
  • @Plutonix. Thanks, again. You're right that the item is better than the index. I'll be using that in my real code. I'm using SharpDevelop Version : 4.2.1.8805-9345aa7c .NET Version : 4.0.30319.34209 By the way, I'm using a public form list because the inventory needs to be reloaded each time the form is run. Is there any other advantage to an actual collection class? This application will not be developed or used by anyone else, so I didn't bother with much OOP. – Nicholas Reiser Dec 02 '15 at 22:45
  • The "problem" with an exposed list is that anything and everything can access it and Do Bad Things to it. It would be the job of a collection class to do that Stuff for all the other actors. Including reloading/refreshing the contents. Some of *that* might not be needed depending on where/how the data is stored. – Ňɏssa Pøngjǣrdenlarp Dec 03 '15 at 01:11
  • @Plutonix, the data is collected from a server database that is read only. No data is saved in this application. When you say that anything and everything can access it, does that mean other applications that I've created that are running on the same machine? I tend to use the same variable names and pretty much always use Public variables, and I haven't noticed any collisions yet... – Nicholas Reiser Dec 03 '15 at 15:15

1 Answers1

0

Thanks to @Plutonix for the help!

Here's the code now working:

Imports System.Linq

Public Class stockstatus
    Public part As String
    Public qty As Double
    Public cost As Double
End Class

Public Partial Class MainForm

    Public ssr As New List(Of stockstatus)

    Public Sub New()
        Me.InitializeComponent()
    End Sub

    Sub MainFormLoad(sender As Object, e As EventArgs)

        ssr = getSSR()
        Dim item As stockstatus = ssr.Where(Function(x) x.part = "CP0065-10N-S").FirstOrDefault
        If item IsNot Nothing Then
            Dim ndx As Integer = ssr.IndexOf(item)
            MsgBox(ndx)   'This works now.  It returns 1.
        End If

    End Sub

    Public Function getSSR() As List(Of stockstatus)
        Dim s As New List(Of stockstatus)
        Dim ss As New stockstatus
        ss.part = "CP0065-0.1U-S"
        ss.qty = 1000.0R
        ss.cost = 0.001R
        s.Add(ss)
        ss = New stockstatus
        ss.part = "CP0065-10N-S"
        ss.qty = 1000.0R
        ss.cost = 0.001R
        s.Add(ss)
        Return s
    End Function

End Class
Ňɏssa Pøngjǣrdenlarp
  • 38,411
  • 12
  • 59
  • 178