如何用指定填充百分比的数据填充二维数组?
例如,有一个数组 10 * 10,需要填充其中 30% 的单元格,因此,30 个单元格包含数据,70 个单元格为空。
该任务是解决另一个更大任务的结果,因此我在下面发布了所有代码。数组生成器方法 -generateData
我有三个解决方案。
第一种解决方案是递归调用遍历数组并逐渐用数据填充空单元格的函数。我们从数组的第零个元素开始,如果还没有达到填充数,就重新调用函数。缺点是递归方法本身不是很好,填充的单元格在一侧误入歧途。一个可能的解决方案是当到达数组的末尾时开始向相反的方向遍历
const getStyle = style => Object.assign({}, style);
const universeStyle = length => ({
position: "relative",
width: `${length * 10}px`,
height: `${length * 10}px`,
fontSize: "0",
border: "1px solid #222"
});
const cellStyle = item => ({
background: `${item.color}`,
display: "inline-block",
boxSizing: "border-box",
width: "10px",
height: "10px"
//border: "1px solid grey"
});
const settingsStyle = () => ({
margin: "10px 0 0 0"
});
const Cell = ({ item }) => (
<div x={item.x} y={item.y} style={getStyle(cellStyle(item))} />
);
class Universe extends React.Component {
render() {
return (
<div style={getStyle(universeStyle(this.props.width))}>
{this.props.data.map(item => item.map(item => <Cell item={item} />))}
</div>
);
}
}
class Settings extends React.Component {
render() {
const {fill} = this.props;
return (
<div style={getStyle(settingsStyle())}>
<button onClick={() => this.props.generateUniverse()}>Generate</button>
<div>
<input
onChange={event => this.props.setFill(event)}
type="range"
value={fill} />
<span>{fill}</span>
</div>
</div>
)
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
fill: 30
};
}
componentDidMount() {
this.generateUniverse()
}
getColor(colors = ['white', 'black']) {
return colors[Math.floor(Math.random() * colors.length)];
}
generateData(width, fill) {
const count = (width * width * fill) / 100;
const getColor = this.getColor;
let current = 0;
const spaceData = Array.from({ length: width }).map((item, y) =>
Array.from({ length: width }).map((item, x) =>
({y: y, x: x, color: 'white'})
))
function fillData(data) {
if (current < count) {
data.forEach((line, y, data) =>
line.forEach((obj, x, line) => {
if (current < count) {
obj.color = getColor();
obj.color === 'black' ? current++ : null;
} else { return data }
})
)
return fillData(data)
}
return data
}
return fillData(spaceData)
}
generateUniverse() {
this.setState({
data: this.generateData(this.props.width, this.state.fill)
});
}
redrawUniverse() {
const idRedraw = setTimeout(() => {
this.setState({
data: this.generateData(this.props.width)
}, this.redrawUniverse);
}, 500);
this.idRedraw = idRedraw;
}
stopRedraw() {
clearTimeout(this.idRedraw)
}
setFill(event) {
console.log(event.target.value)
this.setState({fill: event.target.value})
}
render() {
const [{width}, {data, fill}] = [this.props, this.state];
return (
<div>
<Universe
width={width}
data={data}
/>
<Settings
fill={fill}
setFill={(event) => this.setFill(event)}
stopRedraw={() => this.stopRedraw()}
startRedraw={() => this.redrawUniverse()}
generateUniverse={() => this.generateUniverse()}
/>
</div>
)
}
}
ReactDOM.render(<App width={10} />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
第二种解决方案是随机生成每个点的 X、Y 坐标,如果数组中所需的点已经填充 - 跳过,如果没有 - 填充。重复该过程,直到阵列已满。缺点是填充率高时,空点很少,程序将花费更多时间搜索空值。
const getStyle = style => Object.assign({}, style);
const universeStyle = length => ({
position: "relative",
width: `${length * 10}px`,
height: `${length * 10}px`,
fontSize: "0",
border: "1px solid #222"
});
const cellStyle = item => ({
background: `${item.color}`,
display: "inline-block",
boxSizing: "border-box",
width: "10px",
height: "10px"
});
const settingsStyle = () => ({
margin: "10px 0 0 0"
});
const Cell = ({ item }) => (
<div x={item.x} y={item.y} style={getStyle(cellStyle(item))} />
);
class Universe extends React.Component {
render() {
return (
<div style={getStyle(universeStyle(this.props.width))}>
{this.props.data.map(item => item.map(item => <Cell item={item} />))}
</div>
);
}
}
class Settings extends React.Component {
render() {
const {fill} = this.props;
return (
<div style={getStyle(settingsStyle())}>
<button onClick={() => this.props.generateUniverse()}>Generate</button>
<div>
<input
onChange={event => this.props.setFill(event)}
type="range"
value={fill} />
<span>{fill}</span>
</div>
</div>
)
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
fill: 30
};
}
componentDidMount() {
this.generateUniverse();
}
getRandom(data) {
return data[Math.floor(Math.random() * data.length)];
}
generateData(width, fill) {
const countFillObj = (width * width * fill) / 100;
var currentFillObj = 0;
const getRandom = this.getRandom;
const arr = Array.from(Array(width).keys());
const data = Array.from({ length: width }).map((item, y) =>
Array.from({ length: width }).map((item, x) =>
({y: y, x: x, color: 'white'})
))
if (fill === 100) {
return Array.from({ length: width }).map((item, y) =>
Array.from({ length: width }).map((item, x) =>
({y: y, x: x, color: 'black'})
))
}
while (currentFillObj < countFillObj) {
var [randomX, randomY] = [getRandom(arr), getRandom(arr)];
var currentObj = data[randomX][randomY];
if (currentObj.color === 'white') {
currentObj.color = 'black';
currentFillObj += 1
}
}
return data
}
generateUniverse() {
this.setState({
data: this.generateData(this.props.width, this.state.fill)
});
}
redrawUniverse() {
const idRedraw = setTimeout(() => {
this.setState({
data: this.generateData(this.props.width)
}, this.redrawUniverse);
}, 500);
this.idRedraw = idRedraw;
}
stopRedraw() {
clearTimeout(this.idRedraw)
}
setFill(event) {
this.setState({fill: event.target.value});
this.generateUniverse();
}
render() {
const [{width}, {data, fill}] = [this.props, this.state];
return (
<div>
<Universe
width={width}
data={data}
/>
<Settings
fill={fill}
setFill={(event) => this.setFill(event)}
stopRedraw={() => this.stopRedraw()}
startRedraw={() => this.redrawUniverse()}
generateUniverse={() => this.generateUniverse()}
/>
</div>
)
}
}
ReactDOM.render(<App width={10} />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
第三种解法——写题时出现,你可以尝试在填写概率中输入一个校正因子。并且在遍历数组时,填充/跳过一个点时,填充/跳过下一个点的概率发生变化。
请分享你的想法
有必要计算已经填充的单元格的数量,并在此基础上计算填充下一个单元格的概率。
或多或少是这样的:
该算法使所有可能的填充选项具有相同的可能性。
一个简单但不是最好的算法。
创建一个临时二维数组 tmp(n * m - 1, 1)。根据第一个维度,数字等于最终数组n * m的元素个数,根据第二个- 2。
tmp(i,0) = i; tmp(i,1) = 兰德();
按二维排序。
我们取第一个元素所需的百分比,通过第一个维度的值确定坐标 (x = tmp(i,0)\n, y = tmp(i,0)%n) 并设置一个 (array(x ,y)=1)。
完毕。