使用d3基于其他行向csv添加列

时间:2017-07-11 20:50:33

标签: javascript csv d3.js

我使用D3和JavaScript来操作一些csv数据。这个想法是它记录了人们全天去的地方:他们可能从家里开始,去杂货店,学校,工作等。每当有人从他们所在的位置移动时,都会记录csv文件中的新行。因此,当莎莉醒来时,它会记录Sally,home,当她离开学校时,它会记录Sally,school等。这些地方是任意的,可以按任何顺序进行,并且可能有更多的地方。

我的csv文件如下所示:

name,place
Sally,home
Joe,home
Bill,work
Joe,work
Sally,school
Sally,grocery
Bill,salon
Joe,grocery

我想在同一个人的下一步为每一行添加一列。从本质上讲,我希望数据反映homeschool之间,schoolgrocery之间的转换,或者相邻步骤之间的转换。在第一个数据点,莎莉在家,下次她被提及,她在学校。因此,我希望第一个数据点(而不仅仅是Sally, home)更改为Sally, home, school以反映转换。所以,经过操作后,上面应该是这样的:

name,place,next
Sally,home,school
Joe,home,work
Bill,work,salon
Joe,work,grocery
Sally,school,grocery
Sally,grocery
Bill,salon
Joe,grocery

然后,我想删除每个人的最后一步:基本上,任何没有" next"列(这些可能并不总是最后三行)。最终结果如下:

name,place,next
Sally,home,school
Joe,home,work
Bill,work,salon
Joe,work,grocery
Sally,school,grocery

我唯一的想法是使用嵌套for循环来查找下一个匹配的名称,然后以某种方式添加新列...这是我的尝试,但你不能只是声明一个新的列

d3.csv("data.csv", function(error, data) {
for(i=0; i<data.length; i++){
    for(j=0; j<data.length; j++){
        if (data[i].name === data[j].name){
            data[i].next = data[j].place;
            break;
        }
    }
}
});

任何指向正确方向的人都会非常感激(最终目标是能够将此流程放入D3的Sankey图中,如果有帮助的话)。

2 个答案:

答案 0 :(得分:1)

你是什么意思“但你不能只声明一个像这样的新列?是的,你可以(当然,我正在考虑数据阵列,这是你要使用的,而不是实际的CSV。但是,如果你真的想要保存一个新的CSV文件,请相应地编辑您的问题并删除D3标签,因为D3没有相应的方法。)

我要在代码中做的唯一更改是在外部(j)循环之后的一个位置开始内部(i)循环:

for (i = 0; i < data.length; i++) {
  for (j = i + 1; j < data.length; j++) {
    if (data[i].name === data[j].name) {
      data[i].next = data[j].place;
      break;
    }
  }
}

然后,我们删除没有next属性的对象:

var finalData = data.filter(function(d) {
  return d.next
});

以下是您的数据演示:

var data = d3.csvParse(d3.select("#csv").text());
for (i = 0; i < data.length; i++) {
  for (j = i + 1; j < data.length; j++) {
    if (data[i].name === data[j].name) {
      data[i].next = data[j].place;
      break;
    }
  }
}
var finalData = data.filter(function(d) {
  return d.next
});

console.log(finalData)
pre {
  display: none;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<pre id="csv">name,place
Sally,home
Joe,home
Bill,work
Joe,work
Sally,school
Sally,grocery
Bill,salon
Joe,grocery</pre>

答案 1 :(得分:-1)

是的我知道,这是C#而非Javascript,就像你问题上的标签一样。虽然我最擅长C#,但我很匆忙,我想帮忙...所以这里有一个你可以在Javascript中重新设定的概念。

using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.IO;

namespace ManipulatingCSV_45044259
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            /*here I'm just making a list of string that basically represents each line of your file*/
            List<string> textlines = new List<string>();
            textlines.Add("name,place");
            textlines.Add("Sally, home");
            textlines.Add("Joe,home");
            textlines.Add("Bill, work");
            textlines.Add("Joe,work");
            textlines.Add("Sally, school");
            textlines.Add("Sally,grocery");
            textlines.Add("Bill, salon");
            textlines.Add("Joe,grocery");

            Dictionary<string, string> cummulatedValues = new Dictionary<string, string>();

            //iterates through the lines of text
            foreach (string item in textlines)
            {
                string[] splitted = item.Split(',');//split using the delimiter

                if (cummulatedValues.Keys.Contains(splitted[0]))
                {
                    //we already have this person, lets add something to the entry
                    cummulatedValues[splitted[0]] += "," + splitted[1];
                }
                else
                {
                    //this is a new person, lets create an entry
                    cummulatedValues.Add(splitted[0], splitted[1]);
                }
            }

            //Now we'll write the new file.
            using (StreamWriter sw = new StreamWriter("pathtofile.txt"))
            {
                foreach (KeyValuePair<string, string> item in cummulatedValues)
                {
                    /*Since you want only people who have been to more than 1 place*/
                    if (item.Value.Split(',').Length > 1)
                    {
                        //if there are more than 1 place listed
                        sw.WriteLine(item.Key + "," + item.Value);//write the line
                    }
                }
            }
        }
    }
}