タブ区切りデータの処理
Posted feedbacks - Flatten
Nested Hidden1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #text = open("data.txt").read()
text = """ID Surname Forename Age
1 Sato Hanako 17
0 Suzuki Taro 18
3 Ozawa Ichiro 66
2 Asoh Taro 68
"""
records = [l.split('\t') for l in text.split('\n')][:-1]
header = records.pop(0)
records.sort(key=lambda r: int(r[0]))
for r in [header] + records:
r[1],r[2] = r[2],r[1]
for r in records:
r[3] = "%d" % (int(r[3]) + 1)
for r in [header] + records:
print '\t'.join(r)
|
標準入力から読込 標準出力への出力
1 2 3 4 5 | @header = split(/\t/, <>);
($header[2], $header[1]) = ($header[1], $header[2]);
print join("\t", @header);
print map { ($_->[2], $_->[1])=($_->[1], $_->[2]);$_->[3]++; join("\t", @$_)."\n"; } sort{ $a->[0] <=> $b->[0] } map [split /\t/], <> ;
|
sortを使いawkを使わない解。bashとdashで動作確認。
1、3、4、5行目にはタブ文字が含まれています。
1 2 3 4 5 6 | IFS=' '
read -r id forename surname age
echo "$id $surname $forename $age"
sort -n -t ' ' | while read -r id forename surname age;do
echo "$id $surname $forename $((age + 1))"
done
|
標準入力から標準出力へ $ runghc tsv.hs < tsv.data ID Forename Surname Age 0 Taro Suzuki 19 1 Hanako Sato 18
1 2 3 4 5 6 7 8 9 10 11 12 13 | import Control.Arrow
import Data.Function
import Data.List
main :: IO ()
main = putStr . unlines . map (concat . intersperse "\t") . uncurry (++)
. second (map inccol4 . sortBy (compare `on` readInt . head))
. splitAt 1 . map (swap23 . words)
. filter (not . null) . lines =<< getContents
where swap23 (x:y:z:ws) = x:z:y:ws
inccol4 (x:y:z:[w]) = x:y:z:[show (readInt w+1)]
readInt :: String -> Int
readInt = read
|
効率すこし改善版
1 2 3 4 5 6 7 8 9 10 11 12 | import Control.Arrow
import Data.Function
import Data.List
main :: IO ()
main = mapM_ (putStrLn . concat . intersperse "\t") . uncurry (++)
. (map (swap23 . words) *** sortBy (compare `on` readInt . head) . map (swap23inccol4 . words))
. splitAt 1 . filter (not . null) . lines =<< getContents
where swap23 (x:y:z:ws) = x:z:y:ws
swap23inccol4 (x:y:z:[w]) = x:z:y:[show (readInt w+1)]
readInt :: String -> Int
readInt = read
|
統計処理言語だけあって、Rでは、この手のデータ処理は非常に直感的です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | # タブ区切りのデータを読み込む
d <- read.delim("input.tsv")
# 第1カラムの値でデータを昇順にソートする。
d <- d[sort.list(d[,1]),]
# 第2カラムと第3カラムをヘッダを含めて入れ替える。
d[,c(2,3)] <- d[,c(3,2)]
colnames(d)[c(2,3)] <- colnames(d)[c(3,2)]
# 第4カラムの値にそれぞれ1を加える。
d[,4] <- d[,4] + 1
# 書き出す
write.table(d, "output.tsv", sep="\t", quote=F, row.names=F)
|
何とか。 しかし何か美しくない...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | #include <algorithm>
#include <functional>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>
namespace
{
class Row
{
std::vector<std::string> data_;
friend std::istream& operator>>(std::istream&, Row&);
friend std::ostream& operator<<(std::ostream&, const Row&);
public:
std::size_t find(const std::string& key) const;
std::string& operator[](std::size_t i)
{ return data_.at(i); }
const std::string& operator[](std::size_t i) const
{ return data_.at(i); }
bool empty() const
{ return data_.empty() || data_.size() == 1 && data_[0] == ""; }
};
std::istream&
operator>>(std::istream& is, Row& r_)
{
Row r;
std::string line;
std::getline(is, line);
std::string::size_type i, o = 0;
while ((i = line.find("\t", o)) != std::string::npos)
{
r.data_.push_back(line.substr(o, i - o));
o = i+1;
}
r.data_.push_back(line.substr(o));
std::swap(r, r_);
return is;
}
std::ostream&
operator<<(std::ostream& os, const Row& r)
{
std::copy(r.data_.begin(), r.data_.end(), std::ostream_iterator<std::string>(os, "\t"));
os << "\n";
return os;
}
std::size_t
Row::find(const std::string& key)
const
{
std::vector<std::string>::const_iterator it =
std::find(data_.begin(), data_.end(), key);
if ( it == data_.end() )
throw "not found";
return std::distance(data_.begin(), it);
}
typedef Row Header;
class Table
{
Header header_;
std::vector<Row> rows_;
friend std::istream& operator>>(std::istream&, Table&);
friend std::ostream& operator<<(std::ostream&, const Table&);
public:
void sort_by(std::size_t idx);
void swap_columns(std::size_t col1, std::size_t col2);
template <typename Filter>
void filter(std::size_t idx, Filter f);
private:
class comparator
: public std::binary_function<bool, Row, Row>
{
std::size_t col_;
public:
comparator(std::size_t col) : col_(col) {}
bool operator()(const Row& r1, const Row& r2) const
{ return r1[col_] < r2[col_]; }
};
};
std::istream&
operator>>(std::istream& is, Table& t)
{
is >> t.header_;
std::istream_iterator<Row> b(is),e;
std::copy(b, e, std::back_inserter(t.rows_));
if (t.rows_.back().empty())
t.rows_.erase(t.rows_.end() - 1);
return is;
}
std::ostream&
operator<<(std::ostream& os, const Table& t)
{
os << t.header_;
std::copy(t.rows_.begin(), t.rows_.end(), std::ostream_iterator<Row>(os, ""));
return os;
}
void
Table::sort_by(std::size_t idx)
{
comparator comp(idx);
std::sort(rows_.begin(), rows_.end(), comp);
}
void
Table::swap_columns(std::size_t col1, std::size_t col2)
{
if ( col1 == col2 ) return;
std::swap(header_[col1], header_[col2]);
std::vector<Row>::iterator it = rows_.begin();
for ( ; it != rows_.end(); ++it )
std::swap((*it)[col1], (*it)[col2]);
}
template <typename Filter>
void
Table::filter(std::size_t idx, Filter f)
{
std::vector<Row>::iterator it = rows_.begin();
for ( ; it != rows_.end(); ++it )
{
std::stringstream ss((*it)[idx]);
typename Filter::result_type v;
ss >> v;
v = f(v);
ss.clear();
ss << v;
(*it)[idx] = ss.str();
}
}
int filter(int i)
{ return i+1; }
} // namespace
int main()
{
std::istringstream ss(
"ID\tSurname\tForename\tAge\n"
"1\tSato\tHanako\t17\n"
"0\tSuzuki\tTaro\t18\n"
);
Table t;
ss >> t;
std::cout << t << "\n=====\n";
t.sort_by(0);
t.swap_columns(1,2);
t.filter(3, std::ptr_fun(filter));
std::cout << t << "\n";
return 0;
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Sample {
private List<String> header;
private List<List<String>> data;
public Sample(String str) {
boolean isFirst = true;
String[] lines = str.split("\n");
data = new ArrayList<List<String>>(lines.length - 1);
for (String line : str.split("\n")) {
List<String> row = Arrays.asList(line.split("\t"));
if (isFirst && !(isFirst = false)) {
header = row;
} else {
data.add(row);
}
}
}
public Sample sort(final int column) {
Collections.sort(data, new Comparator<List<String>>() {
public int compare(List<String> l, List<String> r) {
return r.get(column).compareTo(l.get(column));
}
});
return this;
}
public Sample swapColumn(final int column1, final int column2) {
List<List<String>> list = new ArrayList<List<String>>(data);
list.add(0, header);
forAll(list, new Closure() {
public void each(List<String> row) {
row.set(column1, row.set(column2, row.get(column1)));
}
});
return this;
}
public Sample addValue(final int column, final int add) {
forAll(new Closure() {
public void each(List<String> row) {
row.set(column,
Integer.toString(Integer.parseInt(row.get(column)) + add));
}
});
return this;
}
private void forAll(Closure c) {
forAll(data, c);
}
private void forAll(List<List<String>> list, Closure c) {
for (List<String> row : list) {
c.each(row);
}
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(join(header)).append("\n");
for (List<String> row : data) {
builder.append(join(row)).append("\n");
}
return builder.toString();
}
private String join(List<String> list) {
StringBuilder builder = new StringBuilder();
boolean isFirst = true;
for (String str : list) {
if (!isFirst) {
builder.append("\t");
} else {
isFirst = false;
}
builder.append(str);
}
return builder.toString();
}
private static interface Closure {
public void each(List<String> row);
}
public static void main(String[] args) {
String str =
"ID\tSurname\tForename\tAge\n" +
"1\tSato\tHanako\t17\n" +
"0\tSuzuki\tTaro\t18\n";
System.out.println(
new Sample(str).sort(1).swapColumn(1, 2).addValue(3, 1));
}
}
|
Squeak Smalltalk で。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | | data cr numRows numCols table rIdx labels rows |
data := 'ID Surname Forename Age
1 Sato Hanako 17
0 Suzuki Taro 18
3 Ozawa Ichiro 66
2 Asoh Taro 68'.
cr := Character cr.
numRows := (data occurrencesOf: cr) + 1.
numCols := ((data upTo: cr) occurrencesOf: Character tab) + 1.
table := Matrix rows: numRows columns: numCols.
rIdx := 0.
data linesDo: [:line |
| cIdx |
rIdx := rIdx + 1.
cIdx := 0.
line tabDelimitedFieldsDo: [:each | table at: rIdx at: (cIdx := cIdx + 1) put: each]].
labels := table atRow: 1.
table atColumn: 4 put: (table atColumn: 4) + 1.
table atRow: 1 put: labels.
table swapColumn: 2 withColumn: 3.
labels := table atRow: 1.
rows := (2 to: table rowCount) collect: [:idx | table atRow: idx].
rows sort: [:a :b | a first < b first].
World findATranscript: nil.
{labels}, rows do: [:each |
Transcript cr.
each do: [:elem | Transcript show: elem] separatedBy: [Transcript tab]]
"=>
ID Forename Surname Age
0 Taro Suzuki 19
1 Hanako Sato 18
2 Taro Asoh 69
3 Ichiro Ozawa 67 "
|
Python Code Reading 4に出てきたmetaclassをつかってみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | def readheader(line):
class _Meta(type):
def __init__(cls, name, bases, dct):
cls._attrnames = tuple(line.split('\t'))
class TSVObject(object):
__metaclass__ = _Meta
def __init__(self, line):
attrvalues = tuple(line.split('\t'))
self.__dict__.update(dict(zip(self._attrnames, attrvalues)))
def __str__(self):
return '<TSVObject %s>'%(','.join(['%s=%s'%(key, value) for key, value in self.__dict__.items()]),)
__repr__ = __str__
return TSVObject
def parse(lines):
klass = None
L = list()
for line in lines:
if klass is None:
klass = readheader(line)
continue
L.append(klass(line))
return L
data = (
'''ID\tSurname\tForename\tAge\n'''
'''1\tSato\tHanako\t17\n'''
'''0\tSuzuki\tTaro\t18\n'''
)
lines = data.splitlines()
L = parse(lines)
def cmp(a, b):
a = int(a.ID), int(b.ID)
if a > b:
return -1
elif b < a:
return 1
return 0
L.sort(cmp)
print '%s\t%s\t%s\t%s'%('ID', 'Forename', 'Surname', 'Age')
for item in L:
print '%s\t%s\t%s\t%s'%(item.ID, item.Forename, item.Surname, int(item.Age)+1)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | (defpackage :doukaku-209 (:use :cl :split-sequence))
(in-package :doukaku-209)
(defun parse-integer-or-never (string &key (after #'values))
(let ((num (parse-integer string :junk-allowed 'T)))
(if num (funcall after num) string)))
(with-open-file (in "doukaku-209.data")
(with-open-file (out "doukaku-209.out" :direction :output :if-exists :supersede)
(format out "~{~{~A~^ ~}~%~}"
(destructuring-bind (title &rest data)
(loop :for (id sur fore age) := (split-sequence #\Tab (read-line in nil nil))
:while (and id sur fore age)
:collect (list (parse-integer-or-never id)
fore
sur
(parse-integer-or-never age :after #'1+)))
`(,title ,@(sort data #'< :key #'first))))))
|
(with-open-file (in "doukaku-209.data")
(update-file (make-instance 'doukaku-209) in *standard-output*))
;>>>
ID Forename Surname Age
0 Taro Suzuki 19
1 Hanako Sato 18
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | (defpackage :doukaku-209 (:use :cl :split-sequence))
(in-package :doukaku-209)
(defclass file-op () ())
(defgeneric file-to-data (file-op stream))
(defgeneric swap-colum (file-op data))
(defgeneric sort-data (file-op data))
(defgeneric update-datum (file-op data))
(defgeneric format-out-data (file-op stream data))
(defgeneric update-file (file-op in-stream out-stream))
(defmethod update-file ((op file-op) (in stream) (out stream))
(format-out-data op out
(swap-colum op
(destructuring-bind (title &rest data) (file-to-data op in)
`(,title ,@(sort-data op (loop :for line :in data
:collect (update-datum op line))))))))
(defclass doukaku-209 (file-op) ())
(defmethod file-to-data ((op doukaku-209) (in stream))
(loop :for line := (read-line in nil nil) :while line
:collect (split-sequence #\Tab line)))
(defmethod swap-colum ((op doukaku-209) (data list))
(loop :for xx :in (copy-list data)
:do (rotatef (nth 1 xx) (nth 2 xx))
:collect xx))
(defmethod sort-data ((op doukaku-209) (data list))
(sort (copy-list data) #'< :key #'first))
(defmethod format-out-data ((op doukaku-209) (out stream) (data list))
(format out "~{~{~A~^ ~}~%~}" data))
(defmethod update-datum ((op doukaku-209) (row list))
(destructuring-bind (id sur fore age) row
(list (parse-integer id)
sur
fore
(1+ (parse-integer age)))))
|
項目の入れ替えが行われていない
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | using System;
using System.Collections.Generic;
using System.Text;
using VB_IO = Microsoft.VisualBasic.FileIO;
class Program {
static void Main(string[] args) {
//テーブルの準備
List<string> headers = new List<string>();
List<List<string>> table = new List<List<string>>();
//TSVの読み込みにはMicrosoft.VisualBasic.FileIOTextFieldParserクラスが便利。CSVにも使えるよ。
//Microsoft.VisualBasicを参照に加えてね。
using(VB_IO.TextFieldParser tfp = new VB_IO.TextFieldParser(args[0], Encoding.GetEncoding("shift-jis"))) {
tfp.SetDelimiters("\t");//区切り記号はタブ
//通常のテキストファイルと同じ感覚で扱えます。
headers.AddRange(tfp.ReadFields());
while(!tfp.EndOfData) {
table.Add(new List<string>(tfp.ReadFields()));
}
tfp.Close();
}
//第1カラムの値でデータを昇順にソートする。
table.Sort((a, b) => (int.Parse(a[0]) - int.Parse(b[0])));//何回見ても書いてもラムダ式きもい。
//第2カラムと第3カラムをヘッダを含めて入れ替える。
headers.Reverse(1, 2);
foreach(List<string> row in table){
row.Reverse(1, 2);
//第4カラムの値にそれぞれ1を加える。
row[3] = (int.Parse(row[3]) + 1).ToString();
}
//出力
foreach(string header in headers){
Console.Write(header + "\t");
}
Console.WriteLine();
foreach(List<string> row in table) {
foreach(string cell in row) {
Console.Write(cell + "\t");
}
Console.WriteLine();
}
}
}
|
なぜか、ここまで Ruby が無かったので投稿。
こういうデータを扱うための、CSV というそのものズバリのクラスがあります。
データは標準入力から読み込み。
# もう少しすっきりと書けそう。
1 2 3 4 5 6 7 8 9 | require 'csv'
rows = CSV.parse(STDIN.read, "\t")
rows[1], rows[2] = rows[2], rows[1]
result = []
result << rows.shift
rows.sort_by{ |r| r[0] }.
inject(result) { |a, b| b[3] = b[3].to_i + 1; a << b }.
each { |r| puts r.join("\t") }
|
1. ファイルの終わりまで繰り返す 1.1. 1行を読む 1.2. \tでsplitして*r=vector<string>に格納 1.3. swapで入れ替え 1.4. rをvector< vector<string> >に格納 2.1. 並び替え 2.2. \tをはさみながらjoinして表示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/join.hpp>
#include <boost/foreach.hpp>
using namespace std;
using namespace boost::algorithm;
typedef vector<string> row;
bool comp(row* lhs, row* rhs) {
return atoi((*lhs)[0].c_str()) < atoi((*rhs)[0].c_str());
}
int main()
{
vector<row*> all;
string line;
while (getline(cin,line)) {
row* r=new row();
split(*r,line,is_any_of("\t"));
swap((*r)[1],(*r)[2]);
all.push_back(r);
}
sort(all.begin()+1,all.end(),comp);
BOOST_FOREACH(row* r, all) cout<<join(*r,"\t")<<endl;
}
|
「第4カラムの値にそれぞれ1を加える」が抜けてますよー
あまりScalaらしくありませんが...。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | object Tsv {
def tsv(text:String) : Unit = {
import scala.io.Source
val lines = Source.fromString(text).getLines
print(lines.next)
val data = lines.map({s:String => s.split("\t")})
val lst = List.fromIterator(data).sort({(a:Array[String], b:Array[String]) => Integer.parseInt(a(0)) < Integer.parseInt(b(0))})
for (line <- lst) {print(line(0) + "\t" + line(1) + "\t" + line(2) + "\t" + line(3))}
}
def main(args : Array[String]) : Unit = {
val testData = "ID\tSurname\tForename\tAge\n1\tSato\tHanako\t17\n0\tSuzuki\tTaro\t18\n"
tsv(testData)
}
}
|
ご指摘ありがとうございます。修正しました。 1. ファイルの終わりまで繰り返す 1.1. 1行を読む 1.2. \tでsplitして*r=vector<string>に格納 1.3. swapで入れ替え 1.4. 1を加える 1.5. rをvector< vector<string> >に格納 2.1. 並び替え 2.2. \tをはさみながらjoinして表示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | #include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/join.hpp>
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
using namespace std;
using namespace boost;
using namespace boost::algorithm;
typedef vector<string> row;
bool comp(row* lhs, row* rhs) {
return lexical_cast<int>((*lhs)[0]) < lexical_cast<int>((*rhs)[0]);
}
int main()
{
vector<row*> all;
string line;
while (getline(cin,line)) {
row* r=new row;
split(*r,line,is_any_of("\t"));
swap((*r)[1],(*r)[2]);
try { (*r)[3]=lexical_cast<string>(lexical_cast<int>((*r)[3])+1); }
catch (const bad_lexical_cast&) {}
all.push_back(r);
}
sort(all.begin()+1,all.end(),comp);
BOOST_FOREACH(row* r, all) cout<<join(*r,"\t")<<endl;
}
|
ファイルから読んでファイルへ書き出します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | using System.IO;
using System.Linq;
class Program
{
static void Main()
{
var header =
from line in File.ReadAllLines("inFile.txt").Take(1)
let x = line.Split('\t')
select x[0] + '\t' + x[2] + '\t' + x[1] + '\t' + x[3];
var lines =
from line in File.ReadAllLines("inFile.txt").Skip(1)
let x = line.Split('\t')
orderby x[0]
select x[0] + '\t' + x[2] + '\t' + x[1] + '\t' + (int.Parse(x[3]) + 1);
File.WriteAllLines("outFile.txt", header.Concat(lines).ToArray());
}
}
|
]d=.;:;._2 data レコードを改行で、カラムをタブで区切りboxに入れる。
+--+-------+--------+---+
|ID|Surname|Forename|Age|
+--+-------+--------+---+
|1 |Sato |Hanako |17 |
+--+-------+--------+---+
|0 |Suzuki |Taro |18 |
+--+-------+--------+---+
]h=.0{d 1行目をヘッダに。J言語ではリストやテーブルの
+--+-------+--------+---+ インデックスは0-オリジン。
|ID|Surname|Forename|Age|
+--+-------+--------+---+
]d=.}.d 2行目からをデータに。
+-+------+------+--+
|1|Sato |Hanako|17|
+-+------+------+--+
|0|Suzuki|Taro |18|
+-+------+------+--+
]d=. d /: 0{"1 d 第1カラムの値でデータを昇順にソートする。
+-+------+------+--+
|0|Suzuki|Taro |18|
+-+------+------+--+
|1|Sato |Hanako|17|
+-+------+------+--+
]h=.0 2 1 3{ h ヘッダの第2カラムと第3カラムを入れ替える。
+--+--------+-------+---+
|ID|Forename|Surname|Age|
+--+--------+-------+---+
]d=. 0 2 1 3 {"1 d データの第2カラムと第3カラムを入れ替える。
+-+------+------+--+
|0|Taro |Suzuki|18|
+-+------+------+--+
|1|Hanako|Sato |17|
+-+------+------+--+
]d=.(":&>:&".&.>3{"1 d) 3}"0 1 d 第4カラムの値にそれぞれ1を加える。
+-+------+------+--+ 数値に変換して加算した後、文字列に戻す。
|0|Taro |Suzuki|19|
+-+------+------+--+
|1|Hanako|Sato |18|
+-+------+------+--+
]d=.h,d ヘッダとデータを連結。
+--+--------+--------+---+
|ID|Surname |Forename|Age|
+--+--------+--------+---+
|0 |Taro |Suzuki |19 |
+--+--------+--------+---+
|1 |Hanako |Sato |18 |
+--+--------+--------+---+
]d=.(,TAB&;)/"1 d カラムを区切るタブを挿入。
+--+-+--------+-+-------+-+---+
|ID| |Forename| |Surname| |Age|
+--+-+--------+-+-------+-+---+
|0 | |Taro | |Suzuki | |19 |
+--+-+--------+-+-------+-+---+
|1 | |Hanako | |Sato | |18 |
+--+-+--------+-+-------+-+---+
最後にboxから取り出して出力。
1 2 3 4 5 6 7 8 9 | data =. ;: ;._2 stdin''
header =. 0{data
data =. }.data
data =. data /: 0{"1 data
header =. 0 2 1 3{ header
data =. 0 2 1 3{"1 data
data =. (":&>:&".&.>3{"1 data) 3}"0 1 data
data =. header , data
wd&;"1 (, TAB&;)/"1 data
|
書き捨てっぽく。引き数でファイル名を取って標準出力へ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | (use srfi-1)
(use text.csv)
(define (main args)
(receive (header body) (call-with-input-file (cadr args)
(lambda (port)
(car+cdr (port->list (make-csv-reader #\tab)
port))))
(for-each
(cute (make-csv-writer #\tab) (current-output-port) <>)
(cons (list (first header) (third header) (second header) (fourth header))
(map (cut map x->string <>)
(sort
(map (lambda (vs)
(list (string->number (first vs))
(third vs)
(second vs)
(+ (string->number (fourth vs)) 1)))
body)
(lambda (v1 v2) (< (first v1) (first v2)))))))))
|
バッチで。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | @echo off
setlocal enabledelayedexpansion
set a=0
set d=0
set l=0
set z=
if "%1" == "" (echo %~n0 [FILE] & exit /b 1)
for /f "tokens=1-4" %%a in (%1) do (
echo %%a %%c %%b %%d
goto _BREAK_
)
:_BREAK_
for /f "tokens=1" %%a in ('more +1 %1') do (
if %%a gtr !a! set a=%%a
)
call :length %a% l
for /l %%i in (1,1,%l%) do set z=!z!0
for /f "tokens=1-4" %%a in ('more +1 %1') do (
set a=%z%%%a
set /a d=%%d+1
set %~n0_!a:~-%l%!=%%a %%c %%b !d!
)
for /f "tokens=2 delims==" %%l in ('set %~n0_') do echo %%l
endlocal
goto :EOF
:length
setlocal
set i=0
set t=%~1
if "%t%" == "" endlocal & set %2=0
:_LENGTH_
set t=%t:~1%
set /a i+=1
if not "%t%" == "" goto _LENGTH_
endlocal & set %2=%i%
goto :EOF
|
実行方法: $ cat hoge.txt ID Surname Forename Age 1 Sato Hanako 17 0 Suzuki Taro 18 $ erlc doukaku7723.erl $ erl -noshell -s doukaku7723 main hoge.txt -s init stop ID Forename Surname Age 0 Taro Suzuki 19 1 Hanako Sato 18
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | -module(doukaku7723).
-export([main/1]).
main(Filename) ->
{ok, Bin} = file:read_file(Filename),
A1 = string:tokens(binary_to_list(Bin), "\r\n"),
[H | T] = lists:map(curry(flip(fun string:tokens/2), "\t"), A1),
A2 = lists:map(fun swap23inc4/1, T),
A3 = lists:sort(fun([E1|_], [E2|_]) -> list_to_integer(E1) < list_to_integer(E2) end, A2),
A4 = lists:map(func_comp(fun lists:concat/1, curry(fun intersperse/2, "\t")), [swap23(H) | A3]),
A5 = lists:concat(intersperse("\r\n", A4)),
io:format("~s~n", [A5]).
swap23([A,B,C,D | Rest]) -> [A,C,B,D|Rest].
swap23inc4([A,B,C,D | Rest]) -> [A,C,B,integer_to_list(1+list_to_integer(D)) | Rest].
intersperse(_, []) -> [];
intersperse(_, [X]) -> [X];
intersperse(Sep, [X | XS]) -> [X, Sep | intersperse(Sep, XS)].
curry(F, A) -> fun(B) -> F(A, B) end.
flip(F) -> fun(A, B) -> F(B, A) end.
func_comp(F, G) -> fun(X) -> F(G(X)) end.
|
ほとんど #7724 さんと同じですね・・・でも書いちゃったので投稿。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | def convert(input, output):
# read from file
datas = [line.rstrip('\n').split('\t') for line in open(input)]
# swap column2 and column3 (with header)
for data in datas:
data[1], data[2] = data[2], data[1]
# remove header
header = datas.pop(0)
# sort by column1
datas.sort(key=lambda data: int(data[0]))
# add 1 to column4
for data in datas:
data[3] = str(int(data[3]) + 1)
# restore header
datas.insert(0, header)
# write to file
io = open(output, "w")
for data in datas:
io.write('\t'.join(data) + '\n')
if __name__ == '__main__':
convert("input.txt", "output.txt")
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | let succ_str s =
try (string_of_int (int_of_string s + 1))
with Failure _ -> s
let read scanbuf f =
let t = "\t" and nl = "\n" in
Scanf.bscanf scanbuf "%[^\t]\t%[^\t]\t%[^\t]\t%[^\n]%c"
(fun a b c d _ -> f [a;t;c;t;b;t; succ_str d; nl])
let f ch =
let accu = ref [] in
try
read ch (List.iter print_string);
while true do
(read ch (fun l -> accu := l::!accu))
done;
with End_of_file ->
let l = List.stable_sort (fun a b ->
compare (List.hd a) (List.hd b)) !accu
in List.iter (List.iter print_string) l;;
(*
let s = "\
ID\tSurname\tForename\tAge
1\tSato\tHanako\t17
0\tSuzuki\tTaro\t18
"
let (path,o) =
Filename.open_temp_file "doukaku209_" ".txt";;
output_string o s; close_out o;;
let sbuf = Scanf.Scanning.from_file path in (f sbuf);;
*)
|
1 2 3 4 5 6 7 8 9 | lines = ARGF.readlines
csvs = lines.map {|line| line.split("\t")}
head = csvs.shift
print [head[0], head[2], head[1], head[3]].join("\t")
csvs.sort {|csv1, csv2| csv1[0] <=> csv2[0] }.each do |csv|
puts [csv[0], csv[2], csv[1], csv[3].to_i + 1].join("\t")
end
|
import java.io.*;
import java.util.*;
class Table {
public static void main( String[] args ) {
Table table = new Table()
.input( "in.tsv" )
.sort( 0 )
.replace( 1, 2 )
.increment( 3 )
.output( "out.tsv" );
}
Cell[][] cells;
class Cell {
String value;
Cell( String value ) {
this.value = value;
}
public String toString() { return value; }
public int compareTo( Cell that ) { return this.value.compareTo( that.value ); }
public void increment() { value = ( Integer.parseInt( value ) + 1 ) + ""; }
}
class Sorter implements Comparable {
Cell key;
Cell[] row;
Sorter( Cell key, Cell[] row ) {
this.key = key;
this.row = row;
}
public int compareTo( Object that ) {
return this.key.compareTo( ( (Sorter) that ).key );
}
}
Table input( String file ) {
try {
BufferedReader in = new BufferedReader( new FileReader( file ) );
List<Cell[]> list = new ArrayList<Cell[]>();
String line;
while ( ( line = in.readLine() ) != null ) {
list.add( makeCells( line.split( "\t" ) ) );
}
in.close();
cells = list.toArray( new Cell[0][] );
return this;
} catch ( IOException e ) { throw new RuntimeException ( e ); }
}
Table sort( int ic ) {
Cell[] column = column( ic );
Sorter[] sorters = new Sorter[rows()-1];
for ( int ir = 1; ir < rows(); ++ir ) {
sorters[ir-1] = new Sorter( column[ir], row( ir ) );
}
Arrays.sort( sorters );
for ( int ir = 1; ir < rows(); ++ir ) {
cells[ir] = sorters[ir-1].row;
}
return this;
}
Table replace( int ic1, int ic2 ) {
Cell[] column1 = column( ic1 );
Cell[] column2 = column( ic2 );
set( ic1, column2 );
set( ic2, column1 );
return this;
}
Table increment( int ic ) {
Cell[] column = column( ic );
for ( int ir = 1; ir < rows(); ++ir ) {
column[ir].increment();
}
return this;
}
Table output( String file ) {
try {
PrintWriter out = new PrintWriter( new BufferedWriter( new FileWriter( file ) ) );
out.print( toString() );
out.flush();
out.close();
return this;
} catch ( IOException e ) { throw new RuntimeException( e ); }
}
Cell[] makeCells( String[] array ) {
Cell[] cells = new Cell[array.length];
for ( int i = 0; i < array.length; ++i ) {
cells[i] = new Cell( array[i] );
}
return cells;
}
void set( int ic, Cell[] column ) {
for ( int ir = 0; ir < rows(); ++ir ) {
cells[ir][ic] = column[ir];
}
}
Cell[] row( int ir ) {
Cell[] bak = new Cell[columns()];
for ( int ic = 0; ic < columns(); ++ic ) {
bak[ic] = cells[ir][ic];
}
return bak;
}
Cell[] column( int ic ) {
Cell[] bak = new Cell[rows()];
for ( int ir = 0; ir < rows(); ++ir ) {
bak[ir] = cells[ir][ic];
}
return bak;
}
int rows() { return cells.length; }
int columns() { return cells[0].length; }
public String toString() {
StringBuilder bak = new StringBuilder();
for ( int ir = 0; ir < cells.length; ++ir ) {
for ( int ic = 0; ic < cells[0].length; ++ic ) {
bak.append( ic > 0 ? "\t"
: "" ).append( cells[ir][ic].toString() );
}
bak.append( "\r\n" );
}
return bak.toString();
}
}
なでしこで、手順に忠実に書いてみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | input="ID Surname Forename Age
1 Sato Hanako 17
0 Suzuki Taro 18"
data=inputをTSV取得
# ヘッダを切り取る
head=dataの0を配列切り取る
# 第1カラムでソート
dataの0を表数値ソート
# 第2カラムと第3カラムを入れ替え
data=dataの1と2を表列入替
# ヘッダも入れ替え
head=headの1と2を配列入替
# 第4カラムに1を加算
Iで0から(dataの配列要素数-1)まで繰り返す
data[I][3]=data[I][3]+1
# ヘッダとデータを結合
output=(headの表行列交換)にdataを表追加
# 結果を表示
outputを表TSV変換して表示
●配列入替(AのXとYを)
AのXにA[Y]を配列挿入
AのY+1を配列削除
Aで戻る
●表列入替(AのXとYを)
AのYを表列取得
AのXにそれを表列挿入
それのY+1を表列削除
それで戻る
●表追加(AにBを)
Aの(Aの配列要素数)にBを配列一括挿入
Aで戻る
|
一行Pythonで190 bytes. 標準入力から標準出力へ。 横に広がって見づらいので 適当に改行を入れました。
1 2 3 | import sys;T,N='\t\n';I=int;R=[l[:-1].split(T)for l in sys.stdin];A,B,C,D=R[0];
print N.join(map(T.join,[(A,C,B,D)]+[(a,c,b,str(I(d)+1))for a,b,c,d in sorted(
R[1:],None,lambda x:I(x[0]))])),N
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | def text = new File("test.csv").text
def lines = text.split("\n")
def titles = lines[0].split("\t")
def records = lines[1..-1].collect{
it.split("\t")
}
// 第1カラムの値でデータを昇順にソートする。
records.sort{ it[0] }
// 第2カラムと第3カラムをヘッダを含めて入れ替える。
def change( row ){
def tmp = row[2]
row[2] = row[1]
row[1] = tmp
}
change(titles)
records.each{
change(it)
}
// 第4カラムの値にそれぞれ1を加える。
records.each{ r ->
r[3] = (r[3].toInteger() + 1).toString()
}
([titles] + records).each{
println it.join("\t")
}
|
genzouさんに触発されて書いてみました。
see: Grな日々
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | boolean firstLine = true
def lines = []
new File("test.csv").eachLine {
e = it.split("\t")
if (firstLine) {
println([e[0],e[2],e[1],e[3]].join("\t"))
firstLine = false
}
else {
lines.push(e)
}
}
lines.sort{it[0].toInteger()}.each{
println([it[0],it[2],it[1],it[3].toInteger() +1].join("\t"))
}
|
私も書いてみました。わかりやすさ重視で書いたつもりです。。
1 2 3 4 5 6 7 8 9 10 11 12 | lines = new File('test.csv').readLines()
rows = lines.collect { it.split('\t') }
head = rows.remove(0)
rows.each { row ->
[0, 3].each { row[it] = row[it].toInteger() }
}
rows.sort { it[0] }
[head, *rows].each { tmp = it[1]; it[1] = it[2]; it[2] = tmp }
rows.each { it[3]++ }
[head, *rows].each { println it.join('\t') }
|
私も書いてみました。わかりやすさ重視で書いたつもりです。。
1 2 3 4 5 6 7 8 9 10 11 12 | lines = new File('test.csv').readLines()
rows = lines.collect { it.split('\t') }
head = rows.remove(0)
rows.each { row ->
[0, 3].each { row[it] = row[it].toInteger() }
}
rows.sort { it[0] }
[head, *rows].each { tmp = it[1]; it[1] = it[2]; it[2] = tmp }
rows.each { it[3]++ }
[head, *rows].each { println it.join('\t') }
|
間違えてOtherで投稿しちゃいました。削除はできないんですね。。Groovyに投稿し直します。ごめんなさい。
あまり美しくないですが、基本に忠実に。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | import System.Environment
import Data.List
q1 (x:xs) = x:sortBy (\a b -> compare (toNum a) (toNum b)) xs
where
toNum n = read (head n)::Int
q2 = map (\[i,l,f,a] -> [i,f,l,a])
q3 (x:xs) = x:map (\[i,l,f,a] -> [i,l,f,show $ 1+read a]) xs
main = do
args <- getArgs
contents <- if (not.null) args
then readFile $ head args
else getContents
let rec = map words $ lines contents
putStrLn $ shows $ q1 rec
putStrLn $ shows $ q2 rec
putStrLn $ shows $ q3 rec
where
shows list = unlines $ map (concat.intersperse "\t") list
|
1 | groovy -e '{h,...r->[h,*r.each{it[0,4]*.toInteger()}.each{++it[3]}.sort{it[0]}]*.join("\t").any"".&println}(*"$System.in".trim().split(/\n/)*.split(/\t/)*.getAt([0,2,1,3]))'<data.csv
|
< it[0,4]*.toInteger()
---
> a->[0,3].each{a[it]=0.decode(a[it])}
全然違った。「it[0,3]=it[0,3]*.toInteger()」だとうまくいかなくて残念。
ID Surname Forename Age
1 Sato Hanako 17
0 Suzuki Taro 18
C:\>cscript /nologo csv.js < emp.txt
ID Forename Surname Age
0 Taro Suzuki 19
1 Hanako Sato 18
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | Array.prototype.each = function(iterator){
for(var i=0, length=this.length; i<length; i++) iterator(this[i],i);
}
var table = [];
WScript.StdIn.ReadAll().split('\r\n').each(function(line){
if(!line.match(/^\s*$/)) table.push(line.split('\t'));
});
var header = table.shift();
//第1カラムの値でデータを昇順にソートする
table.sort(function(a,b){return a[0]-b[0];});
//第4カラムの値にそれぞれ1を加える
table.each(function(row){row[3]=row[3]*1+1;});
//第2カラムと第3カラムをヘッダを含めて入れ替える
table.unshift(header);
table.each(function(row){
WScript.StdOut.WriteLine([row[0],row[2],row[1],row[3]].join('\t'));
});
|
はじめまして。最初awk向きなのになぜ未投稿?と思ったのですが、ソートが必要なのですね。 教科書どおりのqsortですが、整数値をソートする、ということで17行目で +0 してから比較してみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | >type data.txt
ID Surname Forename Age
0 Suzuki Taro 19
1 Sato Hanako 18
11 Kato Junko 40
3 Yamammoto Shingo 46
>type tab_sort.awk
BEGIN{FS="\t";OFS="\t"}
NR == 1{ print $1,$3,$2,$4 }
NR > 1{t=$2;$2=$3;$3=t;$4=$4+1;A[NR]=$0;}
END{qsort(A,2,NR)
for(i=2;i<=NR;i++) print A[i]
}
function qsort(A,left,right){
if(left>=right) return
swap(A,left,left+int((right-left+1)*rand()))
last=left
for(i=left+1;i<=right;i++)
#if(A[i] < A[left]) swap(A,++last,i)
if(A[i] + 0 < A[left] + 0) swap(A,++last,i)
swap(A,left,last)
qsort(A,left,last-1)
qsort(A,last+1,right)
}
function swap(A,i,j){
t=A[i];A[i]=A[j];A[j]=t
}
>mawk32 -f tab_sort.awk data.txt > kekka.txt
>type kekka.txt
ID Forename Surname Age
0 Taro Suzuki 20
1 Hanako Sato 19
3 Shingo Yamammoto 47
11 Junko Kato 41
|
はじめまして。最初awk向きなのになぜ未投稿?と思ったのですが、ソートが必要なのですね。 教科書どおりのqsortですが、整数値をソートする、ということで17行目で +0 してから比較してみました。 #最初の投稿時、言語を指定しそこない、otherに投稿してしまいました。申し訳ありません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | >type data.txt
ID Surname Forename Age
0 Suzuki Taro 19
1 Sato Hanako 18
11 Kato Junko 40
3 Yamammoto Shingo 46
>type tab_sort.awk
BEGIN{FS="\t";OFS="\t"}
NR == 1{ print $1,$3,$2,$4 }
NR > 1{t=$2;$2=$3;$3=t;$4=$4+1;A[NR]=$0;}
END{qsort(A,2,NR)
for(i=2;i<=NR;i++) print A[i]
}
function qsort(A,left,right){
if(left>=right) return
swap(A,left,left+int((right-left+1)*rand()))
last=left
for(i=left+1;i<=right;i++)
#if(A[i] < A[left]) swap(A,++last,i)
if(A[i] + 0 < A[left] + 0) swap(A,++last,i)
swap(A,left,last)
qsort(A,left,last-1)
qsort(A,last+1,right)
}
function swap(A,i,j){
t=A[i];A[i]=A[j];A[j]=t
}
>mawk32 -f tab_sort.awk data.txt > kekka.txt
>type kekka.txt
ID Forename Surname Age
0 Taro Suzuki 20
1 Hanako Sato 19
3 Shingo Yamammoto 47
11 Junko Kato 41
|
どうですかね。Rubyっぽいですか?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | lst = []
#全部リスト(lst)に取り込んで
while gets
lst << chomp.split("\t")
end
#Array#mapで第2カラムと第3カラムを入れ替えて
lst.map!{|x|x[0], x[1], x[2], x[3] =
x[0], x[2], x[1], x[3]}
#見出しを出力して
puts lst.shift.join("\t")
#IDを数値にして、Ageに一つ加えて、IDで並び替えて出力
for i in lst.map{|x|[x[0].to_i, x[1], x[2], x[3].next]}.sort
puts i.join("\t")
end
__END__
ID Surname Forename Age
1 Sato Hanako 17
0 Suzuki Taro 18
|
5行目はprintでなくputsじゃないですか。
あと7行目、sortでなくsort_by{|csv| csv[0]}のがよくないですか。
(でもsort_byって昔なかったんですっけ)
俺なりのRubyっぽく、かつ各操作の直交性を意識して書いてみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | str = "ID\tSurname\tForename\tAge
1\tSato\tHanako\t17
0\tSuzuki\tTaro\t18"
#取り込み
data = str.split(/\n/).map{|line| line.split("\t")}
#第2カラムと第3カラムをヘッダを含めて入れ替える。
data.each{|record| t = record[1]; record[1] = record[2]; record[2] = t}
head = data.shift
#第1カラムの値でデータを昇順にソートする。
data = data.sort_by{|record| record[0]}
#第4カラムの値にそれぞれ1を加える。
data.each{|record| record[3].succ!}
#表示
([head]+data).each{|record| puts record.join("\t")}
|
配列とか知ってればもっとスマートにかけたと思うのですが、まだ学習中なので……。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | import List
testdata = "ID\tSurname\tForename\tAge\n" ++
"1\tSato\tHanako\t17\n" ++
"0\tSuzuki\tTaro\t18\n" ++
"2\tTanaka\tYaeko\t16"
readI ::String -> Int
readI = read
mkTable = map words.lines
mkText = unlines .map (concat.intersperse "\t")
sortTable (header:body)= header:sortBy (\a b->compare (readI $ head a) (readI $ head b)) body
swapColumn23 table = map swapItem table
where swapItem [a,b,c,d]=[a,c,b,d]
add1Column4 (header:body)= header:map (reverse.(\(x:xs)->show(readI(x)+1):xs).reverse) body
converter :: String -> String
converter content = mkText $ add1Column4 $ swapColumn23 $ sortTable $ mkTable content
main = interact $ converter
|
Safe C String Library (SafeStr)に,ちょうどsafestr_splitがあるので,それを使ってみました.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 | #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "safestr.h"
#ifndef false
# define false 0
#endif
#ifndef true
# define true !false
#endif
struct item_t {
int is_int;
union {
safestr_t str;
int num;
} value;
};
struct item_t *
create_record_from_list(safestr_t *list)
{
struct item_t *item;
int i;
if ((item = (struct item_t *)malloc(sizeof(struct item_t[4])))
== NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
for (i = 0; i < 4 && list[i] != NULL; i++) {
item[i].is_int = false;
item[i].value.str = list[i];
safestr_reference(list[i]);
}
if (i != 4) {
fprintf(stderr, "ERROR: 4 fields needed.\n");
exit(EXIT_FAILURE);
}
return item;
}
void
convert_int_fields(struct item_t *item)
{
int value;
int i;
for (i = 0; i <= 3; i+=3) {
value = safestr_toint32(item[i].value.str, 0);
safestr_free(item[i].value.str);
item[i].value.num = value;
item[i].is_int = true;
}
}
void
records_dump(struct item_t **list, struct item_t *header,
ssize_t list_size, int *order)
{
int i, j, col;
struct item_t *cur;
safestr_t str = safestr_create("", 0);
safestr_t str_p = str;
for (i = -1; i < list_size; i++) {
cur = (i == -1) ? header : list[i];
for (j = 0; j < 4; j++) {
col = (order == NULL) ? j : order[j];
if (cur[col].is_int) {
safestr_sprintf(&str, SAFESTR_TEMP("%d"),
cur[col].value.num);
str_p = str;
} else {
str_p = cur[col].value.str;
}
printf("%s%s", (j == 0) ? "" : "\t", (char *)str_p);
}
putchar('\n');
}
safestr_free(str);
}
void
records_copy(struct item_t **dest, struct item_t **src,
int record_size)
{
struct item_t *item;
int i, j;
for (i = 0; i < record_size; i++) {
if ((item = (struct item_t *)malloc(sizeof(struct item_t[4])))
== NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
dest[i] = item;
for (j = 0; j < 4; j++) {
dest[i][j] = src[i][j];
if (!dest[i][j].is_int)
safestr_reference(dest[i][j].value.str);
}
}
}
void
records_free(struct item_t **list, int record_size)
{
int i, j;
for (i = 0; i < record_size; i++) {
for (j = 0; j < 4; j++)
if (!list[i][j].is_int)
safestr_release(list[i][j].value.str);
free(list[i]);
}
}
int
compare(const void *former, const void *latter)
{
struct item_t *former_p = *((struct item_t **)former);
struct item_t *latter_p = *((struct item_t **)latter);
return (former_p[0].value.num - latter_p[0].value.num);
}
int
main(int argc, char **argv)
{
safestr_t line, *list;
struct item_t *record, *header = NULL;
struct item_t *records[64], *r_temp[64];
int i, record_size = 0;
int order[4] = { 0, 2, 1, 3 };
memset(&records, 0, sizeof(records));
/* read data from stdin */
while ((line = safestr_readline(stdin)) != NULL) {
list = safestr_split(line, SAFESTR_TEMP("\t"));
record = create_record_from_list(list);
if (header == NULL)
header = record;
else {
convert_int_fields(record);
records[record_size++] = record;
}
safestr_free(line);
safestr_freelist(list);
}
if (record_size == 0)
exit(EXIT_SUCCESS);
/*
* show results
*/
/* #1 */
records_copy(r_temp, records, record_size);
qsort(r_temp, record_size, sizeof(struct item_t *), compare);
printf("Result of #1:\n");
records_dump(r_temp, header, record_size, NULL);
printf("\n");
records_free(r_temp, record_size);
/* #2 */
records_copy(r_temp, records, record_size);
qsort(r_temp, record_size, sizeof(struct item_t *), compare);
printf("Result of #2:\n");
records_dump(r_temp, header, record_size, order);
printf("\n");
records_free(r_temp, record_size);
/* #3 */
records_copy(r_temp, records, record_size);
for (i = 0; i < record_size; i++)
r_temp[i][3].value.num += 1;
printf("Result of #3:\n");
records_dump(r_temp, header, record_size, NULL);
printf("\n");
records_free(r_temp, record_size);
/* finalize */
records_free(records, record_size);
exit(0);
}
|
16行目を修正。
文字列型でソートしてました。
1
10 <
2
3
4
5
6
7
8
9
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | using System.IO;
using System.Linq;
class Program
{
static void Main()
{
var header =
from line in File.ReadAllLines("inFile.txt").Take(1)
let x = line.Split('\t')
select x[0] + '\t' + x[2] + '\t' + x[1] + '\t' + x[3];
var lines =
from line in File.ReadAllLines("inFile.txt").Skip(1)
let x = line.Split('\t')
orderby int.Parse(x[0])
select x[0] + '\t' + x[2] + '\t' + x[1] + '\t' + (int.Parse(x[3]) + 1);
File.WriteAllLines("outFile.txt", header.Concat(lines).ToArray());
}
}
|
分かりやすく書いたつもりです。
**ポイント
ヘッダとデータは #head(), #tail()を使って取得。
ヘッダごと入れ替え時は、列を1本ずつ取得してから、#transpose()で行・列を入れ替え。
**test.tsv
ID Surname Forename Age
1 Sato Hanako 17
0 Suzuki Taro 18
**実行結果
[入力時]
ID Surname Forename Age
1 Sato Hanako 17
0 Suzuki Taro 18
[出力時]
ID Forename Surname Age
0 Taro Suzuki 19
1 Hanako Sato 18
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | // 入力
def list0 = new File('test.tsv').readLines()*.split('\t')
// 第1カラムの値でデータを昇順にソートする。
def list1 = [list0.head(), *(list0.tail().sort{it[0]})]
// 第2カラムと第3カラムをヘッダを含めて入れ替える。
def list2 = [
list1*.getAt(0),
list1*.getAt(2), // ←第2カラムと
list1*.getAt(1), // ←第3カラムの入れ替え
list1*.getAt(3)
].transpose()
// 第4カラムの値にそれぞれ1を加える。
def list3 = [list2.head(),
*(list2.tail().collect{ [*(it[0..2]), it[3].toInteger() + 1] })]
// 出力
println """\
[入力時]
${ list0*.join('\t').join('\n') }
[出力時]
${ list3*.join('\t').join('\n') }\
"""
|
F#で。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #light "off"
open System;
open System.IO;
let reader (stream:TextReader) =
0 |> Seq.unfold
(fun x ->
match stream.ReadLine() with
| null -> None
| s -> Some(s.Split([|'\t'|]), x))
in
let main (input:TextReader) (output:TextWriter) =
let records = reader input in
let header = records |> Seq.take 1 in
let contents =
records
|> Seq.sort_by (fun x -> int x.[0])
|> Seq.map (fun x -> [|x.[0]; x.[1]; x.[2]; string ((int x.[3]) + 1)|])
in
Seq.append header contents
|> Seq.map (fun x -> String.Join("\t", [|x.[0]; x.[2]; x.[1]; x.[3]|]))
|> Seq.iter output.WriteLine
in
main Console.In Console.Out;;
|
python初心者ですが... ちなみにpython2.3では動かないはず。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import sys
def reorderdOutput(line, headerFlag):
line = line.strip()
columns = line.split("\t")
columns[1], columns[2] = columns[2], columns[1]
if headerFlag == 0:
columns[3] = str(int(columns[3]) + 1)
print "\t".join(columns)
## main
inFile = sys.argv[1]
f = open(inFile)
## header line treatment
line = f.readline()
reorderdOutput(line, 1)
## data section treatment
for line in sorted(f):
reorderdOutput(line, 0)
|
Personクラスを定義して、それのインスタンスのリストを作って、それをソートするという余計な手間ばかりをかけてます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | open System.IO
let inputFileName = @"s:\inputData.txt"
let outputFileName = @"s:\outputData.txt"
type Person (st:string[]) =
member this.id = System.Int32.Parse st.[0]
member this.age = (System.Int32.Parse st.[3]) + 1
member this.toFormat () =
this.id.ToString() + "\t" + st.[1] + "\t" + st.[2] + "\t" + this.age.ToString()
let splitReplaceToArr (str:string) =
let strArr = str.Split([|'\t'|])
[|strArr.[0];strArr.[2];strArr.[1];strArr.[3]|]
let linesReadRepToList (inputFileName: string) =
[
use fileReader = new StreamReader(inputFileName)
while not fileReader.EndOfStream do
let line = splitReplaceToArr (fileReader.ReadLine())
yield line
]
let headerArr = List.hd (linesReadRepToList inputFileName)
let personList = List.map (fun arr -> new Person (arr)) (List.tl (linesReadRepToList inputFileName))
let sortedList = List.sortWith(fun (l:Person) (r:Person) -> r.age - l.age) personList
let resultList = (Array.reduce (fun s inStr -> s + "\t" + inStr) headerArr) ::
(List.map (fun (p:Person) -> p.toFormat()) sortedList)
File.WriteAllLines(outputFileName,resultList)
|
Table クラスを作って、それに処理させる、カラム名で処理するという方針で書いて見ました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | open System
open System.IO
open System.Collections.Generic
type Array with
static member Join separator a =
System.String.Join(separator, Array.ConvertAll(a, fun x -> x.ToString()))
type Table() =
let column = new Dictionary<string, int>()
let table = new ResizeArray<obj []>()
let headLine() =
Seq.zip column.Values column.Keys
|> Seq.sort
|> Seq.map snd
|> Seq.to_array
member t.from_file(filename:string) =
if table.Count <> 0 then table.Clear();column.Clear()
use sr = new StreamReader(filename)
let headLine = sr.ReadLine()
let fields = headLine.Split('\t')
let size = fields.Length
Array.iteri (fun i name -> column.Add(name, i)) fields
while not sr.EndOfStream do
let fields = sr.ReadLine().Split('\t')
// printfn "%A" fields
let size = fields.Length
let data =
Array.map
(fun x ->
match System.Int32.TryParse(x) with
| (true, i) -> box i
| (false, _) -> box x
) fields
table.Add(data)
member t.columnNames =
Seq.to_array column.Keys
member t.apply(col, proc) =
let col = column.[col]
for i=0 to table.Count-1 do
table.[i].[col] <- box <| proc (unbox table.[i].[col])
member t.swap(col1, col2) =
let (c1,c2)=(column.[col1],column.[col2])
column.[col1]<-c2
column.[col2]<-c1
for i=0 to table.Count-1 do
let (d1,d2) = (table.[i].[c1] , table.[i].[c2])
table.[i].[c1] <- d2
table.[i].[c2] <- d1
member t.sort(col, cmp) = //安定なソートではない。
let col = column.[col]
table.Sort(fun (a:obj array) (b:obj array) -> cmp (unbox a.[col]) (unbox b.[col]))
member t.to_file(filename:string) =
use sw = new StreamWriter(filename)
let headLine = headLine()
sw.WriteLine(Array.Join "\t" headLine)
table.ForEach(fun x -> sw.WriteLine(Array.Join "\t" x))
do
let t=new Table()
t.from_file "table.txt"
t.sort("ID", fun a b -> a - b)
t.swap("Surname", "Forename")
t.apply("Age", fun x -> x + 1)
t.to_file "table_new.txt"
|





kh
#7723()
Rating2/2=1.00
タブ区切りのデータを読み込んで操作をし書き出す方法を教えてください。 読み込み・書き出しの方法は任意とします。
与えられるデータは:
この入力データに対して以下の操作をしたものを書き出してください:
入力の例:
出力の例:
[ reply ]