用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/cxcscmu/SkillLearnBench --skill run2-csv-robust-loading命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
基于 SOC 职业分类
| name | run2_csv_robust_loading |
| description | Robust CSV loading and type coercion patterns for D3.js applications with multiple data sources |
Practical patterns for loading CSV data with proper type coercion, null handling, and batch operations for multi-file scenarios.
d3.csv("data/stocks.csv").then(rawData => {
const stocks = rawData.map(d => ({
// String fields - trim whitespace
ticker: d.ticker.trim(),
name: d['full name'].trim(),
sector: d.sector.trim(),
country: d.country?.trim() || null,
website: d.website?.trim() || null,
// Numeric fields - parse and handle nulls
marketCap: d.marketCap ? parseFloat(d.marketCap) : null,
returnOnEquity: d.returnOnEquity ? parseFloat(d.returnOnEquity) : null,
revenuePerShare: d.revenuePerShare ? parseFloat(d.revenuePerShare) : null,
fullTimeEmployees: d.fullTimeEmployees ? parseInt(d.fullTimeEmployees) : null,
// Date fields (if applicable)
// dateCreated: d.dateCreated ? new Date(d.dateCreated) : null
}));
// Validate: Log rows with missing critical fields
const incomplete = stocks.filter(s => !s.ticker || !s.sector);
console.log(`Loaded ${stocks.length} stocks (${incomplete.length} incomplete)`);
return stocks;
});
For reusability and clarity:
function coerceStockRow(d) {
return {
ticker: d.ticker.trim(),
name: d['full name'].trim(),
sector: d.sector.trim(),
marketCap: d.marketCap ? parseFloat(d.marketCap) : null,
country: d.country?.trim() || null,
website: d.website?.trim() || null,
returnOnEquity: d.returnOnEquity ? parseFloat(d.returnOnEquity) : null,
revenuePerShare: d.revenuePerShare ? parseFloat(d.revenuePerShare) : null,
beta: d.beta ? parseFloat(d.beta) : null
};
}
d3.csv("data/stocks.csv")
.then(data => data.map(coerceStockRow))
.then(stocks => visualize(stocks));
async function loadAllData() {
const stocks = await d3.csv("data/stocks.csv")
.then(data => data.map(coerceStockRow));
const sectors = await d3.csv("data/sectors.csv")
.then(data => data.map(d => ({
name: d.sector,
description: d.description
})));
return { stocks, sectors };
}
loadAllData().then(data => visualize(data));
For loading price history for each stock:
async function loadStockPrices(tickers) {
const promises = tickers.map(ticker =>
d3.csv(`data/indiv-stock/${ticker}.csv`)
.then(data => ({
ticker,
prices: data.map(d => ({
date: new Date(d.Date),
close: parseFloat(d.Close),
volume: parseInt(d.Volume),
high: parseFloat(d.High),
low: parseFloat(d.Low)
})).sort((a, b) => a.date - b.date)
}))
.catch(err => {
console.warn(`Failed to load prices for ${ticker}:`, err);
return { ticker, prices: [] };
})
);
const allPrices = await Promise.all(promises);
.(
allPrices.( [p., p.])
);
}
stocks = d3.();
prices = (stocks.( s.));
function safeString(value, defaultValue = null) {
if (!value || typeof value !== 'string') return defaultValue;
const trimmed = value.trim();
return trimmed.length > 0 ? trimmed : defaultValue;
}
// Usage
country: safeString(d.country),
website: safeString(d.website, "Unknown")
function safeNumber(value, defaultValue = null) {
if (value === null || value === undefined || value === '') {
return defaultValue;
}
const num = parseFloat(value);
return isNaN(num) ? defaultValue : num;
}
// Usage
marketCap: safeNumber(d.marketCap),
beta: safeNumber(d.beta, 1) // Default beta to 1 if missing
CSV files may have inconsistent column names:
// Define field mapping
const fieldMap = {
'full name': 'name',
'Market Cap': 'marketCap',
'ROE': 'returnOnEquity'
};
function mapFields(row) {
const mapped = {};
for (let [csvKey, appKey] of Object.entries(fieldMap)) {
mapped[appKey] = row[csvKey];
}
return mapped;
}
async function loadData() {
try {
const stocks = await d3.csv("data/stocks.csv");
if (!stocks || stocks.length === 0) {
throw new Error("CSV is empty");
}
return stocks.map(coerceStockRow);
} catch (error) {
console.error("Failed to load CSV:", error);
return []; // Return empty array as fallback
}
}
async function loadWithProgress(files) {
const total = files.length;
let loaded = 0;
const results = await Promise.all(
files.map(file =>
d3.csv(file)
.then(data => {
loaded++;
console.log(`Loaded ${loaded}/${total}`);
return data;
})
)
);
return results;
}
// ✓ Good - parse only what's used
const stocks = data.map(d => ({
ticker: d.ticker,
marketCap: parseFloat(d.marketCap)
}));
// ✗ Avoid - parse everything
const stocks = data.map(d => coerceAllFields(d));
let cachedStocks = null;
function getStocks() {
if (cachedStocks) return Promise.resolve(cachedStocks);
return d3.csv("data/stocks.csv")
.then(data => {
cachedStocks = data.map(coerceStockRow);
return cachedStocks;
});
}
async function* readCSVChunks(url, chunkSize = 100) {
const data = await d3.csv(url);
for (let i = 0; i < data.length; i += chunkSize) {
yield data.slice(i, i + chunkSize).map(coerceStockRow);
}
}
// Unit test example
const testRow = {
ticker: " AAPL ",
'full name': "Apple Inc.",
marketCap: "2676055080960",
country: ""
};
const coerced = coerceStockRow(testRow);
console.assert(coerced.ticker === "AAPL", "Trim failed");
console.assert(coerced.marketCap === 2676055080960, "Parse failed");
console.assert(coerced.country === null, "Empty string handling failed");