using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Collections.ObjectModel;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
public static void Test()
foreach (var categoriesJson in GetCategoriesJson())
foreach (var itemsJson in GetItemsJson())
var catObj = JObject.Parse(categoriesJson);
var ttObj = JObject.Parse(itemsJson);
var gameVersions = new HashSet<string> { "A", "2" };
var categoryIDs = new HashSet<string> { "metals" };
var query = from i in ttObj.SelectTokens("Items[*]").OfType<JObject>()
let categoryId = (string)i["CategoryID"]
let gameVersion = (string)i["GameVersion"]
where categoryIDs.Contains(categoryId) && gameVersions.Contains(gameVersion)
join c in catObj.SelectTokens("Categories[*]") on categoryId equals (string)c["CategoryID"] into joined
from cat in joined.DefaultIfEmpty()
select new JObject(i.Properties()) { new JProperty("CategoryDescription", cat?["CategoryDescription"]) };
var results = query.ToList();
Console.WriteLine(JsonConvert.SerializeObject(results, Formatting.Indented));
static IEnumerable<string> GetItemsJson()
""CategoryID"":""crystalline"",
""CategoryID"":""metals"",
""TechName"":""Metal Salvage"",
""SpawnID"":""scrapmetal"",
""CategoryID"":""outcrop"",
""TechName"":""Limestone Outcrop"",
""SpawnID"":""limestonechunk"",
""CategoryID"":""crystalline"",
""CategoryID"":""metals"",
""TechName"":""Metal Salvage"",
""SpawnID"":""scrapmetal"",
""CategoryID"":""outcrop"",
""TechName"":""Limestone Outcrop"",
""SpawnID"":""limestonechunk"",
""CategoryID"":""metals"",
""TechName"":""Shiny Metal"",
""SpawnID"":""manufactured metal"",
static IEnumerable<string> GetCategoriesJson()
""CategoryID"":""baseupgrades"",
""CategoryDescription"":""Base Upgrades"",
""IncludeCategory"":true,
""CategoryID"":""batteries"",
""CategoryDescription"":""Batteries"",
""IncludeCategory"":true,
""CategoryID"":""blueprint"",
""CategoryDescription"":""Blueprint"",
""IncludeCategory"":false,
// Other category values omitted
""CategoryID"":""baseupgrades"",
""CategoryDescription"":""Base Upgrades"",
""IncludeCategory"":true,
""CategoryID"":""batteries"",
""CategoryDescription"":""Batteries"",
""IncludeCategory"":true,
""CategoryID"":""metals"",
""CategoryDescription"":""metals description"",
""IncludeCategory"":false,
""CategoryID"":""metals"",
""CategoryDescription"":""metals description 2"",
""IncludeCategory"":false,
// Other category values omitted
public static void Main()
Console.WriteLine("Environment version: {0} ({1})", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription , GetNetCoreVersion());
Console.WriteLine("{0} version: {1}", typeof(JsonSerializer).Assembly.GetName().Name, typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine("Failed with unhandled exception: ");
public static string GetNetCoreVersion()
var assembly = typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly;
var assemblyPath = assembly.Location.Split(new[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries);
int netCoreAppIndex = Array.IndexOf(assemblyPath, "Microsoft.NETCore.App");
if (netCoreAppIndex > 0 && netCoreAppIndex < assemblyPath.Length - 2)
return assemblyPath[netCoreAppIndex + 1];