0

I want to compare two list of row data. Right now I want to see if the two list contain the same title in their respective cell values.

What methods with using Smartsheet API C# could I use to sort through the list and compare each select element in each row?

I already have a column name table to search for the column name and reference the actual column id. But I can not seem to fathom how?

Any input would be helpful and I'm sorry if I sound plain dumb but I usually do not ask for help.

I have two sheets in Smartsheet. One sheet contains all the data that is given and as it goes through a process of acceptance or rejection. If completely accepted it is given a status of "Moved to Project". When the code runs it will place all rows with that status to a List that will then be used to move and compare against other list.

The Moved to Project List will be compared to our Project Management Active List.

I am stuck at trying to compare cell values through the API and maybe I'm just looking at it wrong. I've tried Enum Except to compare list but it is not working and I'm thinking I will need to create a nested loop to sort through and compare each element.

        foreach (Row row in rowsToCompare)
        {
            Cell PMOPName = getPMOCellByColumnName(row, "Project Name");
            foreach (Row innerrow in rowsToMove)
            {

                Cell MainTitle = getCellByColumnName(innerrow, "Title");

                if (PMOPName.DisplayValue == MainTitle.DisplayValue)
                {
                    Console.WriteLine("Yes");
                }
                else
                    Console.WriteLine("No");
            }
        }



    static Cell getCellByColumnName(Row row, string columnName)
    {
        return row.Cells.FirstOrDefault(cell => cell.ColumnId == 
        columnMap[columnName]);
    }

    static Cell getPMOCellByColumnName(Row row, string columnName)
    {
        return row.Cells.FirstOrDefault(cell => cell.ColumnId == 
        columnMapPMO[columnName]);
    }
}

Whenever there is a match of title and project name it should output yes and if not a no.

But instead I get a Unhandled Exception: System.ArgumentNullException: Value cannot be null.

I've pinpointed it to the nested loop. I'm sure I just did something stupid.

EDIT: So this is the definition of the map and how it get it's data.

static Dictionary<string, long> columnMap = new Dictionary<string, long>(); 

static Dictionary<string, long> columnMapPMO = new Dictionary<string, 
long();

// Build column map for later reference
   foreach (Column column in sheet.Columns)
      columnMap.Add(column.Title, (long)column.Id);

   foreach (Column column in pmosheet.Columns)
      columnMapPMO.Add(column.Title, (long)column.Id);

EDIT 2: Confirming with Tim the code works but in my instance it is still coming up with an error so I will place the code that I currently have as a whole to see if possible the other functions could be causing issues.

static void Main(string[] args)    
{

 SmartsheetClient ss = new SmartsheetBuilder()
             // TODO: Set your API access in environment variable 
 SMARTSHEET_ACCESS_TOKEN or else here
             .SetAccessToken(token.AccessToken)
             .Build();

        var sheet = ss.SheetResources.GetSheet(
            sheetId,                    // long sheetId
            null,                       // IEnumerable<SheetLevelInclusion> 
            includes
            null,                       // IEnumerable<SheetLevelExclusion> 
            excludes
            null,                       // IEnumerable<long> rowIds
            null,                       // IEnumerable<int> rowNumbers
            null,                       // IEnumerable<long> columnIds
            null,                       // Nullable<long> pageSize
            null                        // Nullable<long> page
        );

        var pmosheet = ss.SheetResources.GetSheet(
            copyId,
            null,
            null,
            null,
            null,
            null,
            null,
            null
        );

        // Build column map for later reference
        foreach (Column column in sheet.Columns)
            columnMap.Add(column.Title, (long)column.Id);

        foreach (Column column in pmosheet.Columns)
            columnMapPMO.Add(column.Title, (long)column.Id);

        // Accumulate rows needing update and archive here
        List<Row> rowsToMove = new List<Row>();
        List<Row> rowsToArchive = new List<Row>();
        List<Row> rowsToCompare = new List<Row>();

        //Loops through the Ideation Sheet and execute function to evaluate 
        //each row and add those row to the move list.

        foreach (Row row in sheet.Rows)
        {
            Row rowToMove = evaluateRowAndBuildUpdates(row);
            if (rowToMove != null)
            { 
                rowsToMove.Add(rowToMove);
            }
        }
        Console.WriteLine("\n");

        foreach (Row row in pmosheet.Rows)
        {
            Row rowtoCompare = compareRowandCopy(row);
            if (rowtoCompare != null)
                rowsToCompare.Add(rowtoCompare);
        }
        Console.WriteLine("\n");

        foreach (Row innerrow in rowsToMove)
        {
            Cell MainTitle = getCellByColumnName(innerrow, "Title");
            foreach (Row row in rowsToCompare)
            {

                Cell PMOPName = getPMOCellByColumnName(row, "Project Name");

                if (PMOPName.DisplayValue == MainTitle.DisplayValue)
                {
                    Console.WriteLine("Yes");
                    break;
                }
                else
                    Console.WriteLine("No");
            }
        }

          System.Environment.Exit(1); //End of Program
}

 static Row evaluateRowAndBuildUpdates(Row sourceRow)
    {
        Row rowToUpdate = null;

        // Find cell we want to examine
        Cell statusCell = getCellByColumnName(sourceRow, "Status");
        if (statusCell.DisplayValue == "Moved to Project")
        {
            Cell remainingCell = getCellByColumnName(sourceRow, "Status");
            Cell titleCell = getCellByColumnName(sourceRow, "Title");
            if (remainingCell.DisplayValue == "Moved to Project")                  
            {
                rowToUpdate = new Row
                {
                    Id = sourceRow.Id,

                };
                Console.WriteLine("Ideation");
            }

            Console.WriteLine(titleCell.DisplayValue + " ID: " + 
            sourceRow.Id.ToString());
        }
        return rowToUpdate;
    }

    static Row compareRowandCopy(Row sourceRow)
    {
        Row rowToCopy = null;

        Cell pmoStatusCell = getPMOCellByColumnName(sourceRow, "Project 
        Name");
        if (pmoStatusCell.DisplayValue != null)
        {
            rowToCopy = new Row
            {
                Id = sourceRow.Id,

            };
        }
        Console.WriteLine("PMO");
        Console.WriteLine(pmoStatusCell.DisplayValue + " ID: " + 
        sourceRow.Id.ToString());
        return rowToCopy;
    }

        static Cell getCellByColumnName(Row row, string columnName)
    {
        return row.Cells.FirstOrDefault(cell => cell.ColumnId == 
        columnMap[columnName]);
    }

    static Cell getPMOCellByColumnName(Row row, string columnName)
    {
        return row.Cells.FirstOrDefault(cell => cell.ColumnId == 
        columnMapPMO[columnName]);
    }
M. Allen
  • 3
  • 4
  • Does the exception occur the first time through the loop, or do you get valid results first? In other words is it data dependent (perhaps an empty cell)? How are columnMap and columnMapPMO defined? – timwells Jan 08 '19 at 19:54
  • @timwells it does seem to happen when it begins in loop and after further studying I do see that the cell variable is empty. Also the defined column maps are as followed static Dictionary columnMap = new Dictionary(); // Map from friendly column name to column Id static Dictionary columnMapPMO = new Dictionary(); – M. Allen Jan 09 '19 at 13:23

1 Answers1

2

Ok, I have two sheets, the project sheet looks like this: enter image description here And the job sheet containing the rows to be inserted looks like this: enter image description here Here is the code:

using System;
using System.Collections.Generic;

// Add nuget reference to smartsheet-csharp-sdk (https://www.nuget.org/packages/smartsheet-csharp-sdk/)
using Smartsheet.Api;
using Smartsheet.Api.Models;
using System.Linq;

namespace sdk_csharp_sample
{
    class Program
    {
        static Dictionary<string, long> columnMap = new Dictionary<string, long>();

        static Dictionary<string, long> columnMapPMO = new Dictionary<string, long>();

        static void Main(string[] args)
        {
            // Initialize client
            SmartsheetClient ss = new SmartsheetBuilder()
                .SetHttpClient(new RetryHttpClient())
                .Build();

            heet insert = ss.SheetResources.GetSheet(...148L, null, null, null, null, null, null, null);

            Sheet pmosheet = ss.SheetResources.GetSheet(...556L, null, null, null, null, null, null, null);

            // Build column map for later reference
            foreach (Column column in insert.Columns)
                columnMap.Add(column.Title, (long)column.Id);

            foreach (Column column in pmosheet.Columns)
                columnMapPMO.Add(column.Title, (long)column.Id);

            IList<Row> rowsToCompare = pmosheet.Rows;
            IList<Row> rowsToMove = insert.Rows;

            foreach (Row innerrow in rowsToMove)
            {
                Cell MainTitle = getCellByColumnName(innerrow, "Title");
                foreach (Row row in rowsToCompare)
                {
                    Cell PMOPName = getPMOCellByColumnName(row, "Project Name");

                    if (PMOPName.DisplayValue == MainTitle.DisplayValue)
                    {
                        Console.WriteLine("Yes");
                        break;
                    }
                    else
                        Console.WriteLine("No");
                }
            }
        }

        static Cell getCellByColumnName(Row row, string columnName)
        {
            return row.Cells.FirstOrDefault(cell => cell.ColumnId ==
            columnMap[columnName]);
        }

        static Cell getPMOCellByColumnName(Row row, string columnName)
        {
            return row.Cells.FirstOrDefault(cell => cell.ColumnId ==
            columnMapPMO[columnName]);
        }
    }
}

As just a nit I modified the order of the loops so that the rows to be added forms the outer loop (assuming there are projects that may not have corresponding line items to insert that don't need to be looked at), and when I find my match for projects I exit the inner loop.

The output looks like this:

enter image description here

I do get all the way through the test, so it seems like your code does the trick. Maybe simplify your sample inputs so that you can verify that you get what you want. That might also tell us if it is a data driven issue.

timwells
  • 341
  • 1
  • 4
  • wow thank you for confirming that it worked. So then that means it has to be coming from something else. I will keep at it but seeing you work this out has my brain going. I'll comment back with my results thanks again. – M. Allen Jan 10 '19 at 13:57
  • Still getting the following error. Unhandled Exception: System.ArgumentNullException: Value cannot be null. Parameter name: source at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source, Func`2 predicate) at SmartSheetAPITest.Program.getCellByColumnName(Row row, String columnName) in C:\Users\marcus.allen\source\Workspaces\Smartsheet Api\SmartSheetAPITest\SmartSheetAPITest\Program.cs:line 241 at SmartSheetAPITest.Program.Main(String[] args) in C:\Users\marcus.allen\source\Workspaces\Smartsheet Api\SmartSheetAPITest\SmartSheetAPITest\Program.cs:line 98 – M. Allen Jan 10 '19 at 14:05
  • Hmmm...it seems like row.Cells in getCellByColumnName is null (that's the source Enumerable). Put a test in the beginning of that function `if (row.Cells == null)` and do a WriteConsole or something that will help identify when and if that condition is true. I can't think of a Smartsheet API case where that would be true, but first let's see if that is the case. – timwells Jan 10 '19 at 19:43
  • Yes I tried that and it is setting to NULL. I am not sure why it is returning a null if the sort before hand should have not included any nulls when returning rows into the rowstoMove or rowstoCompare. But again thank you for your help. If I make any headway I will let you know. @timwells – M. Allen Jan 10 '19 at 19:51
  • Looks like you may be dropping cells in your rowToMove copy (likewise for the rowToCompare). Should be able to fix during object creation `rowToUpdate = new Row {Id = sourceRow.Id, Cells = sourceRow.Cells }` – timwells Jan 10 '19 at 20:08
  • It seems that my actual list that I create does not have the data needed to go compare. I am assuming it is coming from my functions evaluateRow and compareRow. It is not happy with using those list to get any after the fact. – M. Allen Jan 10 '19 at 20:10