連想配列の使い方、要素の参照方法が判らないので教えて下さい
解決済
回答 2
投稿
- 評価
- クリップ 0
- VIEW 153
連想配列の使い方、要素の参照方法が良く判らないので教えて下さい。
jQueryのjqGridで作成されている配列オブジェクトの値をCSVに出力するスクリプトです。
先人のソースを参考にして見よう見まねで、何とか動くようになり、結果をExcelで開くことも出来るのですが、
いわゆる標準的なCSVの形式として、文字列をダブルクォーテーションで囲む、という形式にすることが出来ていません。
列の属性を判断するには、sorttypeというプロパティを持っているのでそれを参照して、文字か数字かを判断すればよいと思っています。
連想配列の並び順が確保できなかったので、列の順番を付けるためにkeyOrderという配列を設けています。
この配列に値の順に、colModelの中のsorttypeプロパティが'int'の場合には数値と見なすという判断ができればよいかと思うのですが、
どのように検索、参照すればよいのでしょうか?
もっと簡単な方法でできるというご意見もあろうことは承知しておりますが、当面の課題におきましてアドバイスをいただければ幸いです。
よろしくご指導ください。
var dt = [
{cd:"A001", name:"鈴木", age:35}
,{cd:"A002", name:"佐藤", age:45}
,{cd:"A003", name:"田中", age:55}
];
var keyOrder = [
"cd",
"name",
"age"
];
$("#list").jqGrid({
data: dt
,datatype: "local"
,colNames:['CD', '名前', '年齢']
,colModel:[
{index:'cd', name:'cd', width:'50px', align:'center'},
{index:'name', name:'name', width:'100px', align:'left'},
{index:'age', name:'age', width:'80px', align:'right', sorttype:'int'},
]
,height: 150
,multiselect: true
,caption: '一覧'
,rowNum: 5
,rowList: [5, 10, 20]
,viewrecords: true
,pager: 'pg01'
});
var ListToCSV = {
export: function() {
var csv_data = "";
var j;
var line;
// 行データを取得する
var sel_list = $('#list').getGridParam('data');
j = 0;
line = "";
var header_list = $('#list').getGridParam('colNames');
// 列属性の取得 --> ここから sorttypeプロパティを取り出したい
var col_list = $('#list').getGridParam('colModel');
// 見出しの値を取得
header_list.forEach(function( key ) {
// chekbox列の除外
if ( key.indexOf('checkbox') == -1) {
if ( j != 0 ) line += ",";
line += key;
j ++;
}
});
line += '\n';
csv_data += line;
// 明細の値を取得
for (var i = 0; i < sel_list.length; i++) {
j = 0;
line = "";
// 連想配列は並び順が保証されないので定義された順番(keyOrder)に書き出す
keyOrder.forEach(function( key ) {
//
// この部分で、keyの値に対応する列のsorttypeというプロパティを参照
//
// col_list[key]['sorttype'] では駄目でした。
if(sel_list[i][key]){
var innerValue = sel_list[i][key]===null?'':sel_list[i][key].toString();
} else {
var innerValue = '';
}
// " を "" に置換
var result = innerValue.replace(/"/g, '""');
// , 又は \n を含んでいる場合は ""で囲う
if (result.search(/("|,|\n)/g) >= 0)
result = '"' + result + '"';
if ( j != 0 ) line += ",";
line += result;
j ++;
//}
});
console.log(">" + line);
line += '\n';
csv_data += line;
}
// 頭にbomコードを付けた
var csv_data_sjis = "\uFEFF" + csv_data;
return csv_data_sjis;
}
}
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
check解決した方法
0
お騒がせしました。
オブジェクトを持つ配列のインデックスを行、プロパティを列とみなした場合、
特定の列の値がキーワードに合致している行を探し、その行の別のプロパティを参照する、
つまりExcel関数でいうVlookupをする方法が判ればよいことに気づきました。
毎度colModelという配列にアクセスしているので不細工ですが、とりあえず動作しましたので、
ご連絡します。
アドバイスを頂きまして有難うございました。
$("#list").jqGrid({
data: dt
,datatype: "local"
,colNames:['CD', '名前', '年齢']
,colModel:[
{index:'cd', name:'cd', width:'50px', align:'center'},
{index:'name', name:'name', width:'100px', align:'left'},
{index:'age', name:'age', width:'80px', align:'right', sorttype:'int'},
]
,height: 150
,multiselect: true
,caption: '一覧'
,rowNum: 5
,rowList: [5, 10, 20]
,viewrecords: true
,pager: 'pg01'
});
var ListToCSV = {
export: function() {
var csv_data = "";
var j;
var line;
// 行データを取得する
var sel_list = $('#list').getGridParam('data');
j = 0;
line = "";
var header_list = $('#list').getGridParam('colNames');
var col_list = $('#list').getGridParam('colModel'); // ##### この行追加
for (var i = 0; i < sel_list.length; i++) {
j = 0;
line = "";
keyOrder.forEach(function( key ) {
// ##### ここから追加
const col = col_list.find((p) => {
return (p.name === key);
});
let intatr = false;
if (col.sorttype){
if (col.sorttype === "int"){
intatr = true;
}
}
// ##### ここまで追加
if(sel_list[i][key]){
var innerValue = sel_list[i][key]===null?'':sel_list[i][key].toString();
} else {
var innerValue = '';
}
// " を "" に置換
var result = innerValue.replace(/"/g, '""');
// , 又は \n を含んでいる場合は ""で囲う
//if (result.search(/("|,|\n)/g) >= 0)
if (result.search(/("|,|\n)/g) >= 0 || intatr == false) // ##### この行修正
result = '"' + result + '"';
if ( j != 0 ) line += ",";
line += result;
j ++;
});
console.log(">" + line);
line += '\n';
csv_data += line;
}
// 頭にbomコードを付けた
var csv_data_sjis = "\uFEFF" + csv_data;
return csv_data_sjis;
}
}
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
0
CSV
コードを見たところ、下記のように扱うようなので、
変数名 | CSV上の扱い |
---|---|
keyOrder |
列名 |
dt |
Object.values() がセル値 |
その前提でコードを書きました。
<pre></pre>
<script>
'use strict';
function toCsv (keys, body) {
const header = keys.map(key => '"' + key.replace(/"/g, '""') + '"').join();
body = body.map(function (obj) {
return this.map(key => '"' + String(obj[key]).replace(/"/g, '""') + '"').join();
}, keys).join('\r\n');
return header + '\r\n' + body;
}
const dt = [
{cd:'A001', name:'鈴木', age:35},
{cd:'A002', name:'佐藤', age:45},
{cd:'A003', name:'"田中\n太郎"', age:55}
];
const keyOrder = ['cd','name','age'];
document.querySelector('pre').append(toCsv(keyOrder, dt));
</script>
RFC4180準拠。
new Map
連想配列の並び順が確保できなかったので、列の順番を付けるためにkeyOrderという配列を設けています。
順番が重要なら連想配列(という名の new Object
)を使用するべきではありません。
new Map
を使用しましょう。
Re: hatsuzo さん
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.21%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
質問への追記・修正、ベストアンサー選択の依頼
think49
2021/02/23 21:11
HTMLを含めた再現コードを書いてください。
もしくは、必要なデータをコピペ可能な形式で書いてください。
こちらで再現できなければ、正確な回答は出来ません。
> 列の属性を判断するには、sorttypeというプロパティを持っているのでそれを参照して、文字か数字かを判断すればよいと思っています。
この部分が理解できません。
hatsuzo
2021/02/24 09:07
think49さん コメントありがとうございました。
すみません。説明が足りませんでした。
$("#list").jqGrid({
data: dt
,datatype: "local"
,colNames:['CD', '名前', '年齢']
,colModel:[
{index:'cd', name:'cd', width:'50px', align:'center'},
{index:'name', name:'name', width:'100px', align:'left'},
{index:'age', name:'age', width:'80px', align:'right', sorttype:'int'},
]
(以下略)
}
dataプロパティはデータの実体となる配列で、colModelプロパティで各列に対する属性が配列で定義されています。
その中の属性の一つとして、sorttypeがあり、その値がintであれば数値属性であることが識別できる
ということです。
データの実体から見ると、
{cd:"A001", name:"鈴木", age:35}
age列が数値属性であるという意味になります。
実際、フレームワーク(intra-mart)を使っているので、再現コードが書けないため、
$("#list").jqGrid({ の部分やデータの実体部分は実ソースには無いものですが、参照可能な
データの形式で追記したものです。
think49
2021/02/24 12:37 編集
説明を努力しているのは伝わりましたが、まだ正確な状況がわかりません。
コピペで動作して、私が「期待するCSV文字列値」を返す関数に修正して頂ければ、修正可能と思います。
簡単にいえば、「入力値のサンプルコード」と「出力値のサンプル文字列」があれば、他は不要です。