6

C#で修正できるようにしたいJSON文字列があります。子の値の1つが特定の値である場合に基づいて、データセットを削除できるようにしたい。

次のように

 {
  "responseHeader":{
    "status":0,
    "QTime":0,
    "params":{
      "explainOther":"",
      "fl":"*,score",
      "indent":"on",
      "start":"0",
      "q":"*:*",
      "hl.fl":"",
      "qt":"",
      "wt":"json",
      "fq":"",
      "version":"2.2",
      "rows":"2"}
  },
  "response":{"numFound":2,"start":0,"maxScore":1.0,"docs":
  [{
        "id":"438500feb7714fbd9504a028883d2860",
        "name":"John",
        "dateTimeCreated":"2012-02-07T15:00:42Z",
        "dateTimeUploaded":"2012-08-09T15:30:57Z",
        "score":1.0
   },
   {
        "id":"2f7661ae3c7a42dd9f2eb1946262cd24",
        "name":"David",
        "dateTimeCreated":"2012-02-07T15:02:37Z",
        "dateTimeUploaded":"2012-08-09T15:45:06Z",
        "score":1.0
    }]
 }}

上記の2つの応答結果があります。子の「id」値が一致したときに親応答結果グループ全体を削除できるようにしたい。たとえば、IDが「2f7661ae3c7a42dd9f2eb1946262cd24」の場合、2番目のグループを削除したいので、結果は次のようになります。 。

{
  "responseHeader":{
    "status":0,
    "QTime":0,
    "params":{
      "explainOther":"",
      "fl":"*,score",
      "indent":"on",
      "start":"0",
      "q":"*:*",
      "hl.fl":"",
      "qt":"",
      "wt":"json",
      "fq":"",
      "version":"2.2",
      "rows":"2"}},
  "response":{"numFound":2,"start":0,"maxScore":1.0,"docs":[
  {
        "id":"438500feb7714fbd9504a028883d2860",
        "name":"John",
        "dateTimeCreated":"2012-02-07T15:00:42Z",
        "dateTimeUploaded":"2012-08-09T15:30:57Z",
        "score":1.0
    }]
  }}

Jsonファイルに対して複数の削除操作を実行する必要があります。Jsonファイルには何千もの結果が含まれている可能性があり、可能な限り最もパフォーマンスの高い方法が本当に必要です。

どんな助けでも大歓迎です。

4

4 に答える 4

5
var jObj = (JObject)JsonConvert.DeserializeObject(json);
HashSet<string> idsToDelete = new HashSet<string>() { "2f7661ae3c7a42dd9f2eb1946262cd24" };

jObj["response"]["docs"]
    .Where(x => idsToDelete.Contains((string)x["id"]))
    .ToList()
    .ForEach(doc=>doc.Remove());

var newJson = jObj.ToString();
于 2012-11-20T17:42:28.623 に答える
5

私は過去10分ほどこれをより良いLINQステートメントに圧縮しようと試みてきましたが、既知のIDのリストが本質的に各要素の評価方法を変更しているという事実は、おそらくそれを取得するつもりはないことを意味します起こる。

        var jObj = (JObject)JsonConvert.DeserializeObject(json);
        var docsToRemove = new List<JToken>();
        foreach (var doc in jObj["response"]["docs"])
        {
            var id = (string)doc["id"];
            if (knownIds.Contains(id))
            {
                docsToRemove.Add(doc);
            }
            else
            {
                knownIds.Add(id);
            }
        }
        foreach (var doc in docsToRemove)
            doc.Remove();

これは、私がテストするためにスピンアップしたくだらない小さなコンソールアプリでうまく機能するようですが、私のテストは上記のサンプルデータに限定されていたので、問題がある場合はコメントを残して修正してください。

価値のあることとして、これは基本的に、フィードする要素の数に関して線形時間で実行されます。これは、この問題に陽気になることなく、アルゴリズムのパフォーマンスがさらに向上する可能性があります。タスク並列ライブラリを使用して、最大100レコードの各ページを独自のタスクにスピンオフし、独自の小さなページを処理してクリーンアップされたJSON文字列を返すワーカーを呼び出します。マルチコアマシンで実行した場合、これは確かに高速になります。それを開始するためのコードを提供できれば幸いですが、提示されている問題の範囲を大幅にオーバーエンジニアリングすることにもなります。

于 2012-11-20T18:09:58.323 に答える
1

上記の答えはどれも私にはうまくいきませんでした、私はそれだけでなく( )からRemove()子供を産まなければなりませんでした。以下の実用的なコード例:Parent.Parent.Remove()Remove()

namespace Engine.Api.Formatters
{
    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
    using System;
    using System.IO;
    using System.Net;
    using System.Net.Http;
    using System.Net.Http.Formatting;
    using System.Net.Http.Headers;
    using System.Threading.Tasks;
    using System.Web.Script.Serialization;
    using System.Xml;
    using System.Xml.Serialization;

    public class ReducedJson
    {
        public dynamic WriteToStreamAsync(object value)
        {
                    var json = new JavaScriptSerializer().Serialize(value);
                    var serializedJson = (JObject)JsonConvert.DeserializeObject(json);
                    foreach (var response in serializedJson["ProductData"]["Motor"]["QuoteResponses"])
                    {
                        response["NetCommResults"].Parent.Remove();
                        foreach (var netCommResult in response["BestPriceQuote"]["NetCommResults"])
                        {
                            netCommResult["Scores"].Parent.Remove();
                        }
                    }

          return serializedJson;
        }
}

これで時間を節約できれば幸いです。

于 2016-09-05T15:16:16.197 に答える
0

私はただ別の答えを見つけます。

var aJson = JsonConvert.DeserializeObject<JObject>(json);
var doc = aJson["response"]["docs"];
JObject docs = new JObject();
docs["docs"] = doc;

// remove
docs.SelectTokens(string.Format("docs[?(@.id == '{0}')]", "2f7661ae3c7a42dd9f2eb1946262cd24")).ToList().ForEach(i => i.Remove());
// replace
aJson.SelectToken("response.docs").Replace(docs["docs"]);
于 2018-10-30T17:58:27.740 に答える